【问题标题】:C++ File I/O Have to re-open file to write to it? [duplicate]C++ 文件 I/O 必须重新打开文件才能写入? [复制]
【发布时间】:2013-12-09 06:51:55
【问题描述】:

我有一个非常简单的代码:

void LookupName( string tname ){ //Checks for name in records.txt and enters it if it does not exist

//Variables
string fname; //Used to store the name
string throwaway; //Used to dispose of extra data
bool found = false; //Used to track if a name is found in the file

//objects
fstream file ( STATS_FILE ); //Open the file

if (file.is_open()) {

    while ( !file.eof() ) {
        getline (file, fname, DELIM); //Fill name
        getline (file, throwaway, '\n'); //throw away rest of line

        cout << "Found: " << fname << " tname: " << tname << '\n';
        Pause();

        if ( fname == tname ) { //Otherwise, continue
            cout << "Found: " << fname << " tname: " << tname << '\n';
            Pause();
            found = true;
        }
    }

    if ( found == false ) { //if the name is not found
        //Reopen the file so that we can write to it
        file.close();
        file.open( STATS_FILE, fstream::in | fstream::out | fstream::app );

        cout << "Not found" <<endl;
        Pause();
        file << tname << ",0,0\n"; //Add it to the file with 0 wins and losses
    }

    //Cleanup
    file.close();
} 
}

这可行,但是如果您在我检查是否找到名称时注意到底部,我必须关闭并重新打开文件。

以下由于某种原因无法正常工作:

void LookupName( string tname ){ //Checks for name in records.txt and enters it if it does not exist

//Variables
string fname; //Used to store the name
string throwaway; //Used to dispose of extra data
bool found = false; //Used to track if a name is found in the file

//objects
fstream file ( STATS_FILE, fstream::in | fstream::out | fstream::app ); //Open the file

if (file.is_open()) {

    while ( !file.eof() ) {
        getline (file, fname, DELIM); //Fill name
        getline (file, throwaway, '\n'); //throw away rest of line

        cout << "Found: " << fname << " tname: " << tname << '\n';
        Pause();

        if ( fname == tname ) { //Otherwise, continue
            cout << "Found: " << fname << " tname: " << tname << '\n';
            Pause();
            found = true;
        }
    }

    if ( found == false ) { //if the name is not found
        cout << "Not found" <<endl;
        Pause();
        file << tname << ",0,0\n"; //Add it to the file with 0 wins and losses
    }

    //Cleanup
    file.close();
} 
}

我很想知道为什么它在第二个示例中不起作用,因为使用正确的标志仅打开文件 1 次似乎更有效,做我需要做的事情并关闭它。

我感觉这可能与光标的位置有关,我曾尝试使用类似 file.seekg(0) 和 file.seekg(0, ios_base::beg) 但它们没有似乎像宣传的那样工作(或者我只是误解了广告)。

我们将不胜感激。

编辑:couts 用于调试。

编辑 2:我想我应该再强调一下这个问题。

问题是第二个示例没有像第一个示例那样写入文件。我知道对 !file.eof() 条件可能会有一些担忧,但在这种情况下,我不在乎它是否运行额外的时间,因为它不会对结果产生负面影响(此外,正在读取的文本文件已正确格式化,因此不会发生这种情况)。

编辑 3: 我创建了一个运行的非常小的程序:

   //Testing bs
fstream file("Test.txt", fstream::in | fstream:: out | fstream::app );
string temp;

//ClearScreen
system(CLEAR_SCREEN);


file << "Line one\n";

getline(file, temp);
file << temp;
file << "Line two\n";

Pause();
return Menu;

只有第一行被写入文件。我打赌 getline 正在改变流的模式,这就是为什么它是不可写的后记。

最终编辑: 经过大量研究,在上述情况下,重新打开文件是最好的解决方案。最终,问题在于 getline() 与 file.getline() 的使用。我必须重写程序的 1000 行中的太多内容才能“正确”完成。这个故事所讲的道德?如果您遇到此问题,请花一些时间研究istream::getlinegetline(string) 之间的区别,并学会确定何时使用哪个,这样您就不会陷入这种情况。幸运的是,我现在不必修复它,但将来可能会为其他人修复。

【问题讨论】:

  • 你可能想从阅读stackoverflow.com/questions/14615671/…开始
  • @TonyD 大量有用的信息,谢谢;但是,这与问题完全无关。我不会标记你的评论,但我也不会投票,不管它值多少钱。
  • 改为以二进制模式打开文件,然后 seekg 将“像宣传的那样”工作
  • @claptrap 我相信你是对的;但是,这似乎不是解决整体问题的方法。谢谢你的提示。
  • @Toby - 使用像 while ( !file.eof() ) 这样的损坏代码,在修复之前,您不能指望其余代码正常工作...

标签: c++


【解决方案1】:

我不能给你一个明确的答案,但我可以根据推论给你一个很好的想法。

您正在使用fstream(文件流),其实例用于处理文件。如果您查看fstream.open (link) 的文档,请注意第二个参数已设置为默认情况下将输入输出到文件。请注意,默认值是其中之一。这意味着当您打开文件时,您不能假设该文件存在。更重要的是,由于您可能是从文件输入的,从fstream 的角度来看,不应该假设如果文件不存在,就应该创建它。

另一种思考方式:我假设您熟悉ifstream(输入文件流)和ofstream(输出文件流),它们通常在C++教程/指南中比fstream更早介绍.如果您查看ifstream (link) 和ofstream (link) 的文档,您会注意到它们都派生自fstream。现在请记住,当您调用ifstream.open 时,如果文件不存在,则不会创建它——而是设置了故障位。相反,当您调用ofstream.open 时,如果该文件不存在,则它创建。

现在,由于ifstreamofstream 都派生自fstream,我们有两种可能性:

  1. ofstream.open 直接派生自 fstream.open(即它没有扩展功能),我们可以合理地期望 fstream.open 创建文件,因为它最初不存在
  2. ifstream.open 直接派生自 fstream.open,我们可以合理地期望 fstream.open 创建一个文件,因为它一开始并不存在

不言而喻,这两个都不是真的; ofstream.openifstream.open 不能都源自同一事物,但它们的作用却不同; fstream.open 不能既做又不做。

如果您考虑一下,第二个选项更有可能,原因如下:如果 ofstream.open 不直接派生自 fstream.open,它所要做的就是添加一个额外的步骤,在其中创建如果文件不存在,则重置该文件,并重置故障位。上述所有行为都可以通过调用父类的open 函数来实现。另一方面,如果ifstream.open 不直接派生自fstream.open(暗示fstream.open 创建文件,因为它最初不存在),ifstream.open 必须是一个完整的重新实现;否则将无法跳过创建不存在文件的步骤。

由于拥有一个重新实现的函数比拥有一个简单地添加一些东西的不同函数效率低,因此fstream.open 更有可能不会创建/打开文件,如果它没有已经存在了。

我意识到这可能不是您问题的最终解决方案,但我认为这应该可以解释为什么您发布的第二个代码块不会(也不应该)工作。当我查看您的第一个代码块(您说它有效)时,我不完全确定它是如何使它工作的,但我猜这与您将 | fstream::append 添加到 @ 的开放模式参数有关987654356@.

我希望这会有所帮助。

【讨论】:

  • 我很抱歉,但似乎您声称第一个有效的原因与第二个无效的原因完全相同。他们都有 fstream::app 。唯一的区别是模式出现的位置。第一个出现在我已经运行完整个文件之后,第二个出现在之前。据我所知(它没有在 cplusplus.com 上列出) fstream 默认是 ios_base::in | ios_base:;out 意味着在它的默认状态下我应该能够写入和读取文件。
  • 正确 - 但前提是文件已经存在。如果该文件尚不存在,则不会创建该文件-这就是我的帖子的重点。我只提到了fstream::append,因为我认为您对它的使用可能是某些事情正常工作而其他事情不正常的原因。但是正如您所指出的,您也可以在第二个代码块中打开文件的位置。所以可能不是这样。
  • 即使您打开的文件存在,第二段代码是否也无法运行?
  • 另一个想法 - 在第二个代码块中,您在尝试输出到文件之前有while (!in.eof()),这基本上保证了当您尝试输出到文件时会设置 eof 位。这〜可能〜导致意外行为。换句话说,当设置了 eof 位时,您可能无法输出到文件。在尝试输出之前尝试调用fstream::clear - 这将重置错误标志。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-30
  • 2020-12-19
相关资源
最近更新 更多