【问题标题】:How to read the 6th character from the end of the file - ifstream?如何从文件末尾读取第 6 个字符 - ifstream?
【发布时间】:2012-09-05 07:49:45
【问题描述】:
void maintainFileName ()
{
    std :: ifstream myfile;
    myfile.open ("zoomLevels.txt");

    if (myfile.is_open ())
    {
        // Move to end of the file, 
        myfile.seekg (0, std::ios::end);

        // and then six characters back to pick up the last file number.
        myfile.seekg (6, std::ios::beg);

        int len = 1;
        char *t = new char[len];

        myfile.read(t, len);
        qDebug () << "\nt: " << *t << "\n";
    }
    else
    {
        qDebug () << "\nsorry";
    }
}

该文件包含以下内容:

78.8115,29.582,1,01.rda
78.8115,29.582,2,02.rda
76.3671,30.2201,1,11.rda
76.3671,30.2201,2,12.rda
78.1908,30.3007,1,01.rda
78.1908,30.3007,2,02.rda
77.3284,29.1415,1,01.rda
77.3284,29.1415,2,02.rda
77.3064,29.1655,1,01.rda
77.3064,29.1655,2,02.rda

该函数返回的值是5,而倒数第六个字符是0
我哪里错了?

【问题讨论】:

  • 您理解了dir 参数的含义错误。这不是一个方向!不过,您可能不是第一个被抓住的人:这完全是误导:它实际上是一个职位!
  • @J.N.看到这个:cplusplus.com/reference/iostream/istream/seekg 是否写在那里:Seeking direction。 :)
  • 非常来自链接:“寻找方向。它是一个 ios_base::seekdir 类型的对象,它指定了偏移量的绝对位置参数 off 被应用。”方向/绝对位置。难怪人们会感到困惑。
  • 以下链接更清晰:en.cppreference.com/w/cpp/io/basic_istream/seekg。仍然有 dir 名称,可能来自标准。

标签: c++ file-io ifstream


【解决方案1】:

寻找文本文件中的任意位置是未定义的行为。 在实践中,它可能会在各种 Unices 下工作,但在哪里都没有 别的。如果以二进制模式打开文件,则查找是合法的。 形式上,如果你以二进制模式打开文件,你可能会得到额外的 nul 最后的字节,但实际上,今天这不是问题。如果你 以二进制模式打开它,但是,您可能会看到其他内容而不是 '\n'在数据中;例如,在 Windows 下,您会看到这两个 字符序列0x0D, 0x0A

当然,在您的代码中,您是从头开始寻找,而不是从 结束。这也是未定义的行为,但大多数时候,它会 只要你在第一线寻找工作。

最后,您显示的数据中倒数第六个字符是 '2',而不是 '0',就像你写的那样。但当然,在系统以外的系统上 Unix,你可以很容易地看到别的东西(或得到一个错误):可能是 Windows 下的'.',或者某些大型机操作系统下的错误(或者可能是'' ')。

【讨论】:

  • 你说的太对了。我在 Linux 上。现在我以二进制模式打开文件,并显示了正确的结果。当然,最后的第一个字符是EOF,所以我的计算是错误的。感谢您的帮助。
  • @AnishaKaul:没有“EOF 字符”。这一定是 C 程序员中最普遍和根深蒂固的误解之一。
  • 但是当我写 myfile.seekg (-7, std::ios::end); 时,它确实显示了 0。但是,如果您实际计算这些值,0 排在倒数第六位!
  • 最后可能有一个'\n'
  • @AnishaKaul 如果您在 Linux 上,这种类型的定位实际上可以工作,即使在文本模式下也是如此(至少对于 g++ 附带的库)。在许多方面,“文本模式”旨在表示“Unix 做什么”。但正如我所说,你算错了。文件中没有 EOF 字符,但每一行都以 '\n' 结尾,它存在于文件中。 (在二进制模式下,在 Windows 下,您必须计算行尾的两个字节。在大型机上,您可能根本无法相对于结尾进行搜索。这种变化是标准制定它的原因未定义的行为。)
【解决方案2】:
myfile.seekg (6, std::ios::beg);

在这里,您将 6 个字符 开始移动,而不是 开始移动。只需使用

myfile.seekg (-6, std::ios::end);

【讨论】:

  • -6 现在显示2 作为结果,而结果应该是0。 :(
  • 它仍然是未定义的行为。
【解决方案3】:

您可以尝试通过文件末尾的 tellg() 确定文件的完整大小并减去您的数字,根据 > 0 对其进行验证,然后再次查找。 如果你尝试这个,你还应该确保文件以二进制模式打开(我记得,可能有缺陷)

myfile.seekg (0, ios::end);
// You have to ensure, myfile.tellg() > 6
myfile.seekg ( myfile.tellg() - 6, ios::beg );

编辑:

seekg 将 std::streamoff 类型作为偏移量。

标准 (ISO/IEC 14882:2003) 对许多人讨论的这个“问题”说了一些非常有趣的事情。

在第 27.2 节中。前向声明,streampos 属于 fpos 类。

如果我们更进一步,我们可以在第 27.4.3.2 节找到 fpos 的要求表,在那里我们可以得到 streamoff 类型的闭包,这里明确的要求是:q = p + o,所以 fpos 类必须定义一个运算符+(偏移量)。由于 fpos 对象还必须定义一个返回类型为 OFF_T 的 O(p) ,这是一个内部类型,但也有一个语句,std::streamoff 的类型为 OFF_T 我们对标准内的定义有一个闭环用于此操作。

所以这个操作应该很好定义。

欢迎其他意见。

【讨论】:

  • 未定义的行为。并且关于在streampos 中添加或减去值可能意味着什么,该标准非常模棱两可。 (标准实际上对streampos的行为提出了不可能的要求。)
  • 我已经编辑过了,为什么这个标准里面定义的很好,其他意见欢迎讨论。
  • 该标准规定在文本文件上显式搜索,而不是 tell 返回的位置,是未定义的行为。你不需要推理。当然,在实践中,streampos 的算术运算不适用于以文本模式打开的文件,除非在 Unix 下。
  • 您能在此处添加参考吗?如果你已经阅读了上面的帖子,我包括了对二进制打开文件的限制。
  • 啊哈,那么你改变了问题。 OP 的文件以文本模式打开。 (但我仍然不太确定在 streampos 中添加或减去 int 可能意味着什么。streampos 包含状态信息以及位置。想想它在宽字符流上可能意味着什么例如,充满了 UTF-8 语言环境。
【解决方案4】:

第一次搜索跳到结尾,第二次跳到开头+6。

用途:

 myfile.seekg(-6, std::ios::end);

【讨论】:

    【解决方案5】:

    首先,转到文件末尾:is.seekg (0, ios::end);,然后保存位置:file_end_position = is.tellg();。现在跳转到那个位置:is.seekg (file_end_position-6, ios::end);,并从末尾读取第 6 个字符:is.read (buf,1);

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main () {
      int file_end_position;
    
      ifstream is;
      is.open ("test.txt", ios::binary );
    
      // get size of file:
      is.seekg (0, ios::end);
      file_end_position = is.tellg();
      is.seekg (0, ios::beg);
    
    
      //go to the end  of the file -6
      is.seekg (file_end_position-6, ios::end);
    
      char buf[1];
    
      // read the 6th character from the end of the file  
      is.read (buf,1);
      is.close();
    
    
    
      delete[] buffer;
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-21
      • 1970-01-01
      • 2022-01-21
      • 2018-04-11
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 2013-03-27
      • 1970-01-01
      相关资源
      最近更新 更多