Форум: "Основная";
Текущий архив: 2003.07.28;
Скачать: [xml.tar.bz2];
ВнизЧтение файла Найти похожие ветки
← →
Sandman25 (2003-07-15 15:42) [0]Добрый день.
Подскажите, пожалуйста, алгоритм для чтения файла.
В файле находятся данные (и управляющие последовательности) для экспорта в Excel, разделенные неким символом (например, "|").
Как наиболее эффективно считывать данные из файла до первого разделителя, при этом игнорируя концы строк?
Пока делаю так:
const FieldsDelimiter = "|";
function ReadFromFile(var F: File): String;
const
MaxLineLength = 500;
var
Ch: char;
ResultLength: integer;
BytesReadCount: integer;
begin
SetLength(Result, MaxLineLength);
ResultLength := 0;
repeat
BlockRead(F, Ch, 1, BytesReadCount);
if BytesReadCount > 0 then
begin
case Ch of
#10, #13: continue;
FieldsDelimiter: break;
end;
inc(ResultLength);
Result[ResultLength] := Ch;
end
else
break;
until false;
SetLength(Result, ResultLength);
end;
procedure SendToExcel(FileName: string);
var
F: File;
S: String;
begin
...
try
AssignFile(F, FileName);
Reset(F, 1);
try
S := ReadFromFile(F);
showmessage(S);
...
finally
CloseFile(F);
end;
...
end;
Но мне не нравится, что я читаю всего по одному символу.
Наверное, можно попробовать считывать в буфер большего размера (модульную переменную) и по мере необходимости получать из нее следующее значение. Но стоит ли, или Delphi и так использует неявное буферирование?
← →
Тфьу (2003-07-15 15:47) [1]Можно использовать ReadLn(FileHandle,AString);
← →
Sandman25 (2003-07-15 15:52) [2]>Можно использовать ReadLn(FileHandle,AString);
Это частный случай буфера большего размера с необходимостью запоминать остаток строки в случае наличия в ней нескольких разделителей. Особенно неприятно получается, если в конце строки нет разделителя, тогда надо объединять несколько строк. Можно ли как-то обойтись без модульных переменных (запоминания контекста между вызовами функции ReadFromFile)?
← →
Serginio (2003-07-15 16:13) [3]http://www.1c.hippo.ru/cgi-bin/predownl.cgi?id=2019
← →
Sandman25 (2003-07-15 16:43) [4]Serginio
Не качается. Вы имели ввиду TTextReader? Спасибо, я уже решил оставить пока все так, как есть. Потом если будет время, исправлю.
← →
Anatoly Podgoretsky (2003-07-15 16:49) [5]Если ты воспользуешься следующим приемом, то у тебя будет одна длинная строка.
LongStr := "";
While not eof(F) do
begin
WtiteLn(F,S);
LongStr := LongStr + " " + S;
end;
Можно закачать так же в TStringList, тогда у тебя будет одна строка без всяких усилий.
← →
Serginio (2003-07-15 17:00) [6]Delphi в TextFile использует кольцевой буффер правда размером 128 байт
TTextBuf = array[0..127] of Char;
TTextRec = packed record (* must match the size the compiler generates: 460 bytes *)
Handle: Integer; (* must overlay with TFileRec *)
Mode: Word;
Flags: Word;
BufSize: Cardinal;
BufPos: Cardinal;
BufEnd: Cardinal;
BufPtr: PChar;
OpenFunc: Pointer;
InOutFunc: Pointer;
FlushFunc: Pointer;
CloseFunc: Pointer;
UserData: array[1..32] of Byte;
Name: array[0..259] of Char;
Buffer: TTextBuf;
end;
← →
Sandman25 (2003-07-15 17:14) [7]Anatoly Podgoretsky
Сразу весь файл качать в память я не могу - он может оказаться слишком большим.
Serginio
Спасибо. Наверное, я все-таки воспользуюсь Readln.
← →
Anatoly Podgoretsky (2003-07-15 17:17) [8]Можно разновидность, ReadLn до первого разделителя и склеивание строки. Все много быстрее посимвольного чтения.
← →
Anatoly Podgoretsky (2003-07-15 17:17) [9]Просто продумать наиболее оптимальный алгоритм, в зависимости от характера твоих данных.
← →
Serginio (2003-07-15 17:28) [10]Я не буду настаивать, но алгоритмов с использованием кольцевого буфера очень много. Лучше набить руку на будущее. И в итоге тот же не оптимизированный TTextReader оказывается быстрее чем ReadLn. Тем более когда данные нужно читать с конца.
← →
Sandman25 (2003-07-15 17:35) [11]ОК, всем спасибо. Вроде понял.
← →
Sandman25 (2003-07-15 18:05) [12]Сделал так, должно быть быстрее.
var
F: TextFile;
ReadString: string;
function ReadFromFile: String;
var
DelimiterPos: integer;
LengthReadString: integer;
begin
LengthReadString := Length(ReadString);
if LengthReadString = 0 then
begin
while not Eof(F) do
begin
Readln(F, ReadString);
if Pos(FieldsDelimiter, ReadString) > 0 then
break;
end;
LengthReadString := Length(ReadString);
end;
DelimiterPos := Pos(FieldsDelimiter, ReadString);
Result := Copy(ReadString, 1, DelimiterPos - 1);
if DelimiterPos <> LengthReadString then
Delete(ReadString, 1, DelimiterPos)
else
SetLength(ReadString, 0);
end;
← →
Serginio (2003-07-15 18:30) [13]Быстрее у тебя не получится так как ты таскаешь данные по буферу (Delete) POS конечно хорошая функция но легче самому пропарсить.
← →
Sandman25 (2003-07-15 18:41) [14]Serginio
Понятно, буду переделывать. Спасибо.
← →
Song (2003-07-15 21:37) [15]CreateFileMapping, MapViewOfFile()
или TFileStream
100% быстрей будет чем у тебя.
У меня в программе файл 40М загружается в память за 2 сек. Далее всё завит от алгоритма его перебора.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.07.28;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.006 c