Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.07.28;
Скачать: CL | DM;

Вниз

Чтение файла   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.015 c
6-91803
BlackAspid
2003-05-20 19:42
2003.07.28
WebBrowser


11-91696
lomman
2002-11-23 00:25
2003.07.28
Опять все тот-же ListView


14-91808
AlexGreG
2003-07-09 05:48
2003.07.28
... Ох уж эти программисты ...


1-91713
VID
2003-07-14 23:39
2003.07.28
Дельфи 5 или код ?


4-91946
greenrul
2003-05-25 15:28
2003.07.28
Перехват нажатия клавиши