【问题标题】:How to check last line of file for new_line character? C++如何检查文件的最后一行是否有 new_line 字符? C++
【发布时间】:2016-08-17 16:21:41
【问题描述】:

如何检查文件的最后一行是否包含“\n”(或换行符)。

这里有两个例子: a file with newline at the end - a file without newline at the end

我当前的代码:

fstream file("filename");
string line;
if (!file.is_open()) throw Exception();
while(getline(file, line))
{
    (checking for lastline)
}

我意识到 getline 不会包含 new_line 字符。我可以遍历每个字符,但是会出现性能问题。有几百万个字符的文件,我不知道如何去最后一行获取 new_line 字符。

--- 编辑 ---

  • 也许我忘了提到我的环境仅是 UNIX。所以我会 仅使用 end_line 字符 '\n'。
  • 其次,我需要 getline 来检查每一行是否存在一些错误(但在这里不相关)。
  • 如果文件无效,我将在 while 循环之前检查我的最后一行,以便我可以啜饮它!
  • 我的图像显示 CR LF,这是我的错误。为错误道歉。应该只有 LF。

【问题讨论】:

  • 怎么样,求到底?请注意,对于文本模式,搜索通常非常 UB,因此请在二进制模式下进行,或检查是否支持它的详细信息。
  • "'\n'(或换行符)" 听起来是一个非常不精确的要求。你真正想达到什么目标?

标签: c++ file newline eof getline


【解决方案1】:

有三种不同的方法来指示新行。

  • 两个字符 CR LF (\r\n):DOS、OS/2、Microsoft Windows、Symbian、DEC RT-1 1
  • 一个字符 CR (\r):Commodore、Apple II、Mac OS(直到版本 9)、Microware OS-9
  • 一个字符 LF (\n):Unix、BeOS、AmigaOS、MorphOS、RISC OS、GNU/Linux、Mac OS X、Multics

不要使用 getline(),它会吃掉换行符。在二进制模式下使用 read()(参见 Cheers and hth. - Alf 评论)。文本模式将替换每个新的行标记 CR LF,并将 CR 替换为 LF。在您的示例中,您有 CR LF 标签。

在二进制模式下,您必须先将一或两个字符减去文件长度,然后 read() 两个字符,然后检查它们是否等于 CR LF。请参阅 Rishit 示例。

【讨论】:

    【解决方案2】:

    您可以使用seekg 跳转到文件中的任何位置。

    file.seekg(-1,ios_base::end);    // go to one position before the EOF
    char c;
    file.get(c);                     // Read current character
    if(c=='\n'){
        cout<<"yes"<<endl;           // You have new_line character
    }
    

    所以我们跳到 EOF 之前的一个位置并读取最后一个字符。如果是新行,就完成了。

    【讨论】:

      【解决方案3】:

      你可以使用

      fgets(string_name, buffer_size, stdin)
      

      fgets() 包括 new_line 字符,不像 gets() 和
      与 puts() 不同,fputs() 排除了 new_line 字符

      http://www.cplusplus.com/reference/cstdio/fgets/

      例子:

      while( fgets(str, sizeof(str), stdin) ) {
          // check newline at end of string
          int len = strlen(str);
      
          if( str[ len-1 ] != '\0' ) {
              str[ len-1 ] = '\0'; // make sure there's no new_line at the end
              len--;
          }
      
          // now check for empty string, if thus, then last line
          if( strcmp(str, "") == 0 ) break;
      }
      

      【讨论】:

      • 如果行长于缓冲区怎么办?
      • 那么剩下的字符会在缓冲区中,直到缓冲区没有被清空为止。
      • 明白你的意思。它会将其余字符留在缓冲区中,但将 str 中的最后一个字符替换为 '\0'!!!
      • if( str[ len-1 ] != '\0' ) 应该是if( str[ len-1 ] == '\n' ) 吗? (因为 strlen 会将 len 设置为 str 中第一个 nul 的索引,所以我可以看到在索引 len-1 处检测到 nul 的唯一方法是 str 的长度为零(len 为零),因为这种情况是没有检查,一个虚假的 nul 可能碰巧在字符串开始之前存在,在索引 -1 处,但这不是故意的,当然)。
      【解决方案4】:

      getline 的问题在于它读取行并将它们放入 std::string 中,但会去除换行符。您需要的是使用二进制模式读取功能。最困难的任务是让它找到所有可能的新行组合,并处理各种文件大小,最后让它看起来很优雅。下面是我尝试如何做到这一点。

      问题是,例如,如果您的平台将换行存储为 '\r\n',那么如果 \n 或 \r,也算作最后一行的换行?

      http://coliru.stacked-crooked.com/a/06f70dd4ef5c63c8

          std::ofstream ofs("test.txt");
          ofs << "test \n" << "test 2\n";
          //ofs << "\r";
          ofs.close();
      
          std::ifstream ifs("test.txt", std::ifstream::binary);
      
          // Read last two chars, it might also read only one last char
          std::vector<char> end_file_chars;
          for (int pos = 1; pos <= 2; ++pos) {
              if (!ifs.seekg(-pos, std::ios::end)) break;
              char c;
              if (ifs.get(c)) end_file_chars.insert(end_file_chars.begin(), c);
          }
      
          // Possible end file characters
          std::vector<std::vector<char>> endlines = {{'\r', '\n'},
                                                     {'\n'},
                                                     {'\r'}};
      
          // Predicate to compare possible endline with what was found in the file.
          auto checkFn = [&](auto &endline) {
              // Equal compares possible endline in reverse order
              return std::equal(endline.rbegin(), endline.rend(), end_file_chars.rbegin());
          };
      
          // If any end file character was read and if it acually is end file character...
          if (!end_file_chars.empty() && std::find_if(endlines.begin(), endlines.end(),checkFn) != endlines.end()) {
              std::cout << "Found";
          }
          else {
              std::cout << "Not Found";
          }
      

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 2019-12-03
        • 1970-01-01
        • 2020-01-27
        • 1970-01-01
        • 2011-02-03
        • 2021-12-29
        • 1970-01-01
        • 2015-08-13
        相关资源
        最近更新 更多