БлогNot. C++: читаем файл построчно, если длина строки не ограничена

C++: читаем файл построчно, если длина строки не ограничена

В этой лекции написано:

Если максимальная длина строки принципиально не ограничена, помочь может либо предварительное посимвольное чтение файла для её определения, либо работа с файлом как с бинарными данными

На самом деле, и то, и другое. Попробуем прочитать построчно файл, максимальная длина строки которого не ограничена, точней, ограничена только возможностями нашей оперативной памяти.

Идея состоит в том, чтобы сначала при посимвольном чтении файла найти максимальную длину строки maxlen, считая, что все строки заканчиваются символом "перевод строки" \n. Символ "возврат каретки" \r, который в Windows-системах добавляется перед переводом строки, при этом игнорируется, чтобы не получить на единицу большей длины, чем нужно.

После этого выделяем память под буфер длиной maxlen+3 (на всякий случай, чтобы учесть \r, \n и возможный нуль-терминатор) и затем во втором цикле читаем файл уже построчно стандартной функцией fgets. У меня очередная строка файла просто выводится в консоль, на самом деле строки можно поочередно обрабатывать вместо комментария "//Обработка строки buf".

Проверено в консоли Visual Studio 2015.

#define _CRT_SECURE_NO_WARNINGS 
#include <iostream> 
#include <cstdlib> 
#include <windows.h> 
using namespace std;

void error(int n) {
 char *msg[] = { "OK","Can't open file","Can't allocate memory" };
 cout << endl << msg[n]; system("pause>nul"); exit(n);
}

int main() {
 setlocale(LC_ALL, "Russian");
 FILE *f = fopen("data.txt", "rb");
 if (!f) error(1);
 int len = 0, maxlen = 0;
 char c;
 while (1) { //При первом чтении файла находим максимальную длину строки
  fread(&c, 1, 1, f);
  if (c == '\r') continue; //Игнорируем символ "возврат каретки"
  int e = feof(f); //Это конец файла?
  if (c == '\n' || e) { //Последняя строка тоже может оказаться самой длинной!
   if (len > maxlen) maxlen = len;
   len = 0;
  }
  else len++;
  if (e) break;
 }
 cout << "Max. length of string = " << maxlen << endl;

 //Выделяем память для одной строки и встаём на начало файла:
 char * buf = new char[maxlen + 3];
 if (!buf) error(2);
 fseek(f, 0L, SEEK_SET);

 while (1) { //При втором чтении читаем строками
  fgets(buf, maxlen + 2, f);
  int len = strlen(buf);
  if (len && buf[len - 2] == '\r' && buf[len - 1] == '\n') {
   //Если это формат текстового файла  из DOS/Windows (CR/LF)
   buf[len - 2] = '\n'; buf[len - 1] = '\0';
  }
  //Обработка строки buf
  fputs(buf, stdout); //Сама добавит \n при выводе
  if (feof(f)) break;
  buf[0] = '\0';
 }
 fclose(f);
 error(0);
}

Так как мы не работаем с капризной в Studio функцией fgetc, вот таких проблем у нас не возникнет.


теги: c++ форматы textprocessing учебное

11.12.2018, 14:30; рейтинг: 724