Читать строку с помощью TFileStream delphi

Как мне прочитать файл, используя определенные строки TFileStream. Я читаю строки, в которых есть миллионы файлов. Итак, я хочу поиграть в память, которую я буду использовать только

Пример:

Line 1: 00 00 00 00 00 00 00 00
Line 2: 00 00 00 00 00 00 00 00
Line 3: 00 00 00 00 00 00 00 00
Line 4: 00 00 00 00 00 00 00 00
Line 5: 00 00 00 00 00 00 00 00

Я прочитал строки со 2 по 4

Я использовал функцию TextFile, но она кажется медленной. Только что нашел функцию, которая читает последнюю строку в TFileStream.


person André    schedule 22.07.2012    source источник
comment
возможный дубликат потоков чтения построчно   -  person ain    schedule 22.07.2012


Ответы (3)


Вы можете открыть файл для чтения с помощью класса TFileStream вот так ...

FileStream := TFileStream.Create( 'MyBigTextFile.txt', fmOpenRead)

TFileStream не является объектом с подсчетом ссылок, поэтому обязательно отпустите его, когда закончите, например ...

FileStream.Free

С этого момента я буду предполагать, что кодировка символов вашего файла - UTF-8, а завершение конца строки - в стиле MS. В противном случае внесите соответствующие изменения или обновите свой вопрос.

Вы можете прочитать одну кодовую единицу символа UTF-8 (это не то же самое, что чтение одного символа) следующим образом:

var ch: ansichar;
FileStream.ReadBuffer( ch, 1);

Вы можете прочитать такую ​​строку текста ...

function ReadLine( var Stream: TStream; var Line: string): boolean;
var
  RawLine: UTF8String;
  ch: AnsiChar;
begin
result := False;
ch := #0;
while (Stream.Read( ch, 1) = 1) and (ch <> #13) do
  begin
  result := True;
  RawLine := RawLine + ch
  end;
Line := RawLine;
if ch = #13 then
  begin
  result := True;
  if (Stream.Read( ch, 1) = 1) and (ch <> #10) then
    Stream.Seek(-1, soCurrent) // unread it if not LF character.
  end
end;

Чтобы прочитать строки 2, 3 и 4, предполагая, что позиция находится в 0 ...

ReadLine( Stream, Line1);
ReadLine( Stream, Line2);
ReadLine( Stream, Line3);
ReadLine( Stream, Line4);
person Sean B. Durkin    schedule 22.07.2012
comment
Это будет мучительно медленно для большого файла. Вызов ReadFile по одному байту может повредить. - person David Heffernan; 22.07.2012
comment
На самом деле да. Буферы O / S, но при вызове ReadFile возникают большие накладные расходы. Один из моих ответов здесь подробно описывает это. - person David Heffernan; 22.07.2012
comment
Эффективно это или нет, во многом зависит от контекста и ваших ожиданий. OP будет легко настраивать и читать по частям. Но приведенное выше решение - это все, что нужно OP, чтобы понять основную идею. Существует так много бесчисленных вариантов повышения эффективности. Но все это зависит от контекста, и такую ​​оптимизацию лучше оставить на усмотрение OP. - person Sean B. Durkin; 22.07.2012
comment
Что ж, оптимизация понадобится, если нужно читать много строк. Ответ, о котором я говорю, находится здесь: stackoverflow.com/questions/5639531/ - person David Heffernan; 22.07.2012
comment
Спасибо за ответ. В delphi 7 выдается код ошибки Stream.Seek (soCurrent, -1) Существует перегруженная версия Seek, которую можно вызвать с этими аргументами. Формат - UTF8. - person André; 22.07.2012
comment
просто поменяйте местами параметры, и все будет в порядке: Stream.Seek(-1, soCurrent). Вы действительно должны уметь разобраться с этим самостоятельно. Не бойтесь читать документацию. Вот как я это решил. - person David Heffernan; 22.07.2012
comment
Андре, ваш пример предполагает, что ваши линии имеют фиксированный размер. В этом случае вы можете рассчитать смещения строк в потоке. Это было бы очень быстро. И если количество строк, которые вам нужно прочитать, мало по сравнению с размером файла, не читайте весь файл, а используйте BlockRead () и т. Д., Чтобы читать только эти части с диска. - person Jan Doggen; 23.07.2012
comment
Спасибо! Я изучаю реализацию предложенных ресурсов. Все строки будут считываться фиксированного размера - person André; 23.07.2012

Вы можете использовать традиционные файловые операции. Чтобы быть действительно быстрым, вы должны быть уверены, что каждая строка содержит одинаковое количество байтов.

Blockread, BlockWrite, Seek - ключевые слова, на которые вы можете обратить внимание.

Образец страницы для BlockRead

Образец страницы для поиска

person Ali Avcı    schedule 23.07.2012
comment
+1, чтобы противодействовать голосу против. Учитывая ответы Андре на мой комментарий. Возможно, ваши строки фиксированного размера? возможна опция BlockRead () / Seek (). - person Jan Doggen; 23.07.2012

Предложение Шона работает медленно из-за TFileStream.Read, как объяснил Дэвид. Но если вы используете TMemoryStream вместо TFileStream, медленный Stream.Read не так важен. В таком случае большую часть времени занимают строковые операции.

Если немного изменить код, скорость будет примерно в 2 раза выше:

function ReadLine(Stream: TStream; var Line: string): boolean;
var
  ch: AnsiChar;
  StartPos, LineLen: integer;
begin
  result := False;
  StartPos := Stream.Position;
  ch := #0;
  while (Stream.Read( ch, 1) = 1) and (ch <> #13) do;
  LineLen := Stream.Position - StartPos;
  Stream.Position := StartPos;
  SetString(Line, NIL, LineLen);
  Stream.ReadBuffer(Line[1], LineLen);
  if ch = #13 then
    begin
    result := True;
    if (Stream.Read( ch, 1) = 1) and (ch <> #10) then
      Stream.Seek(-1, soCurrent) // unread it if not LF character.
    end
end;
person nfc1    schedule 13.02.2016