【问题标题】:Is my fstream bad or not good()?我的 fstream 是坏还是不好()?
【发布时间】:2012-04-24 15:39:00
【问题描述】:

所以我有一个 .cpp 文件,其中有一个接收文件名的函数,并且应该返回一个包含文件内容的字符串(实际上修改了内容,我修改了代码以使其更易于理解,但没有对我的问题有任何影响)。问题是 f.good() 正在返回 false 并且读取文件的循环不起作用。 代码:

#include "StdAfx.h"
#include "Form21.h"
#include <string>
#include <fstream>
#include <iostream>



    string ReadAndWrite(char* a){
    char filename[8];
    strcpy_s(filename,a);
    string output;
    char c;
    ifstream f(filename,ios::in);
    output+= "Example text"; // <-- this writes and returns just fine!
    c = f.get();

    while (f.good())
      { 

    output+= c;
    c= f.get();         
          }

    return output;
}

有人知道为什么会这样吗? 它是否与这是一个单独的 .cpp 文件有关(当我删除 #include &lt;fstream&gt; 时它甚至不会抛出错误)。 也许有一种不同的方法来制作循环? 我很高兴听到有关如何解决此问题的任何建议可能是有关如何实现我的目标的不同方法。

【问题讨论】:

    标签: c++ iostream fstream


    【解决方案1】:

    首先,没有理由复制您收到的文件名——您可以按原样使用它。其次,几乎所有while (stream.good())while (!stream.bad())while (stream) 等形式的循环几乎肯定是有问题的。您通常要做的是检查读取某些数据是否有效。

    或者,您可以完全跳过使用循环。有几种方法可以做到这一点。一个适用于较短文件的方法如下所示:

    string readfile(std::string const &filename) { 
        std::ifstream f(filename.c_str());   
        std::string retval;
    
        retval << f.rdbuf();
        return retval;
    }
    

    这在处理几十 KB(左右)的数据时效果很好,但在处理较大的文件时会开始变慢。在这种情况下,您通常希望使用ifstream::read 来获取数据,大致如下:

    std::string readfile(std::string const &filename) {
        std::ifstream f(filename.c_str());
    
        f.seekg(0, std::ios_base::end);
        size_t size = f.tellg();
    
        std::string retval(size, ' ');
        f.seekg(0);
        f.read(&retval[0], size);
        return retval;
    }
    

    编辑:如果您需要处理单个字符(而不仅仅是读取它们),您有几个选择。一种是将其分成多个阶段,您在一个阶段中读取所有数据,并在单独的阶段中进行处理。另一种可能性(如果您只需要在处理过程中查看单个字符)是使用std::transform 之类的东西来读取数据,进行处理,然后将输出放入字符串中:

    struct character_processor { 
        char operator()(char input) { 
            // do some sort of processing on each character:
            return ~input;
        }
    };
    
    std::transform(std::istream_iterator<char>(f),
                   std::istream_iterator<char>(),
                   std::back_inserter(result),
                   character_processor());
    

    【讨论】:

    • 看,问题是在循环中我实际上需要分析每个字符,并将一些字符更改为不同的字符,我也会添加行。也许我的想法一直停留在我的方法上,但我不确定我是否能通过你建议的方法实现我想要的。
    【解决方案2】:

    我会检查 strlen(a) 是否不大于 7... 您可能会超出filename 并获得一个不存在的文件名。

    不涉及问题,我会重写函数:

    string ReadAndWrite(string a) {  // string here, if you are into C++ already
        string filename;  // also here
        filename = a;  // simpler
        string output;
        char c;
        ifstream f(filename.c_str());  // no need for ios::in (but needs a char *, not a string
        output+= "Example text"; // <-- this writes and returns just fine!
        f >> c;  // instead c = f.get();
    
        while (f) // no need for f.good())
          { 
    
            output+= c;
            f >> c; // again, instead c= f.get();         
          }
    
        return output;
    }
    

    【讨论】:

    • 即使我用所需的文件名静态“001.txt”更改“文件名”,它仍然不起作用:/
    • operator>> 与 get() 不同。默认情况下,operator>> 将在执行对变量的读取之前删除所有进行中的空白。
    • 这个while(f)while(f.good()) 一样糟糕。在正常情况下,您两者都不会使用。
    【解决方案3】:

    我可以建议使用 fopen 吗? http://www.cplusplus.com/reference/clibrary/cstdio/fopen/ 它接受一个文件名并返回一个文件指针。这样您就可以使用 fgets 逐行读取文件http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

    【讨论】:

    • 请不要!!! :-) C++ 流更方便、更安全、自动关闭等......这就是这样做的方法,但需要知道如何使用它们
    • C 语言没问题。但流更胜一筹。如果您在 C++ 中使用 fopen,则意味着您不会利用该语言,并编写更易受攻击的代码。就像在 C 中使用 goto 或 asm 变量赋值一样。
    猜你喜欢
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    相关资源
    最近更新 更多