2015-04-07 2 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 без спецификации. это имеет значение ? коды работают для чтения ... @Christophe – Noam

+0

Проблема в вашем подходе - многобайтовые символы UTF8. Возьмем пример небольшого pi: его кодировка UTF8 равна 0xCF 0x80. Если вы пишете на своем выходе 0x80 0xCF, это недопустимая последовательность UTF8. Но та же проблема возникает из-за окон для любого текста: '\ n' закодирован в файлах как 0x0D 0x0A. При чтении в текстовом режиме вы получите только «\ n» при чтении этой последовательности. Но с вашим подходом вы сначала позиционируете на 0x0A, вы получите «\ n», а затем вы поместите на 0x0D, который будет считан как «\ n» снова (потому что за ним следует 0x0A). Таким образом, вы будете удваивать каждую новую строку. – Christophe

ответ

1

Если вы хотите просто взять двоичные данные в подарок в обратном порядке, независимо от его значения, ваш код в порядке.

Некоторые рекомендации:

  • Вы должны затем открыть поток в binary для последовательности accross платформы (т.е. избежать, что новая строка преобразуется в двойной перевод строки на платформах, таких как окна, которые кодируют как 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, для которого (u & 0xC0) == 0x80, вы должны прочитать все предыдущие символы, пока это условие не становится ложным, и выход из группы байтов (от 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

Смежные вопросы