2015-04-07 82 views
1

我想从文件向后读取 - 从结尾到开头。 这是有效的,但不仅我想从文件中获取字符,我想在读取时删除它们。反向读取文件,C++ ifstream

std::fstream fileA; 
fileA.seekg(-1, fileA.end); 
int size = fileA.tellg(); 
for (i = 1; i <= size; i++) 
{ 
    fileA.seekg(-i, fileA.end); 
    fileA.get(ch); 

    std::cout << ch; 
} 

有无论如何要做到这一点,没有复制的内容和创建一个新的文件没有我已阅读?

+0

“这工作”:我想知道你是否试过一个utf8文件 – Christophe

+0

记事本说它是UTF 8没有BOM。那很重要吗?代码适用于阅读... @Christophe – Noam

+0

您的方法中存在的问题是多字节UTF8字符。我们以小pi为例:它的UTF8编码是0xCF 0x80。如果您在输出0x80 0xCF中写入,则这是一个无效的UTF8序列。但是,在任何文本的windows下都会出现同样的问题:'\ n'在文件中编码为0x0D 0x0A。在文本模式下阅读时,只有在阅读该序列时才会得到'\ n'。但是用你的方法,你将首先定位在0x0A上,然后你将得到'\ n',然后你将定位在0x0D上,这将再次被读作'\ n'(因为它后面跟着0x0A)。所以你会把每一条新线都加倍。 – Christophe

回答

1

如果您只是想将二进制数据以相反顺序呈现,无论其含义如何,您的代码都可以。

一些建议:

  • 你应该再binary打开流的防空火炮的平台的一致性(即避免换行符在平台上的双新行转化,如编码作为0x0d,0x0a窗口)。

  • 你也可以考虑在循环中使用相对位置到当前位置,向后导航,而不是从最后的绝对位置开始到最后并重新分配。

这里微调代码:

ifstream fileA("test.txt", ios::binary); // binary data because binary revert 
fileA.seekg(-1, ios::end); // position on last char to be read 
char ch; 
for (; fileA.get(ch); fileA.seekg(-2, ios::cur)) // try to read and rewind. 
    std::cout << ch; 

您的代码却无法读取正确的UTF8编码的文件,因为多字节序列将被mecanically revereted,他们恢复的版本是无效的UTF8 :

  • 如果您的文件中只有ASCII码字符,这不是问题。
  • 如果UTF8一致性对于你的问题,你可以考虑一个非常简单的解决方法:如果你读了这(u & 0xC0) == 0x80字符u,你必须直到这个条件变为假读取所有前面的字符,并且输出组字节(2到8之间)以正确的顺序排列。

这里如何做到这一点:

...       // If UTF-8 must be processed correctly 
fileA.seekg(-1, ios::end); 
char ch, buft[9]{},*p; 
bool mb=false; 
for (; fileA.get(ch); fileA.seekg(-2, ios::cur)) 
{ 
    if (mb) { // if we are already processing a multibyte sequence 
     if ((ch & 0xC0) == 0x80 && p!=buft) // still another byte ? 
      *--p=ch; 
     else { 
      cout <<ch<<p; // if no other output the current leading char followed by the multibyte encoding that we've identified 
      mb=false;  // and multibyte processing is then finished 
     } 
    } 
    else if ((ch & 0xC0) == 0x80) { // if a new multibyte sequence is identified 
     mb =true;  // start its processing 
     buft[7]=ch; 
     p=buft+7; 
    } 
    else std::cout << ch; // normal chars ar procesed as before. 
} 

这里一个runnable demo

最后一点:从输入流中移除最后一个字节取决于操作系统。你应该看看this SO question以获得如何在linux/posix和windows上执行它的答案。

2

如果没有使用概述或here的方法之一,这是不可能的。如果在一个istream_iterator看你会发现它是一个输入迭代器(24.6.1)(1)

类模板istream_iterator是一个输入迭代

从(24.2

然后。1)(表105)

Random Access -> Bidirectional -> Forward -> Input 
              -> Output 

正如你可以看到一个输入迭代是更具限制性的正向迭代器和一个前向迭代可以仅在一个方向走。由于这种行为,他们不是一个标准的方式来开始在输入流的结尾,并向后退步

+0

说是没有标准的迭代器,可以做的伎俩并不意味着有做它的标准方式。对于这两个相关的问题/答案仍然是赞同的。特别是'mmap()'方法值得考虑。 – cmaster