16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"RE:TStrings 高速ファイル読み込み"
この発言は #00629 本田勝彦 さんのTStrings 高速ファイル読み込み に対するコメントです
本田勝彦 さんこんにちは。
バグってました(^^ゞ
バッファに読み込む際、ファイル内の #13#10 が分断されると空白行が1行
余計に挿入されてしまいます。
$2000 バイト以上のファイルを読み込むと1/256の確率で発生することが
判明致しました。
バグレポートを下さった染川さんに多謝 m(_ _)m
せっかくなので、#26 ( EOF ) 以降を読み込まないバージョンを書きます。
procedure LoadFromFile(Strings: TStrings; const FileName: String);
const
BufferSize = $2000;
var
I, ReadCount, LineCount: Integer;
LineRemained: Boolean;
S, Str: String;
Buffer, P, Start: PChar;
Fs: TFileStream;
begin
Strings.BeginUpdate;
try
Strings.Clear;
Fs := TFileStream.Create(FileName, fmOpenRead);
try
Buffer := StrAlloc(BufferSize + 1);
try
// #13#10 をカウントする #26 以降は読み込まない
LineCount := 0;
LineRemained := False;
repeat
ReadCount := Fs.Read(Buffer^, BufferSize);
if ReadCount > 0 then
LineRemained := False;
Buffer[ReadCount] := #0;
P := Buffer;
// バッファによって #13#10 が分断された場合のために
if P^ = #10 then Inc(P);
while not(P^ in [#0, #26]) do
begin
while not (P^ in [#0, #10, #13, #26]) do Inc(P);
if P^ in [#10, #13] then
Inc(LineCount)
else
LineRemained := True;
if P^ = #13 then Inc(P);
if P^ = #10 then Inc(P);
end;
if P^ = #26 then Break;
until ReadCount = 0;
if LineRemained then
Inc(LineCount);
// 取得した行数分の Capacity を確保
for I := 0 to LineCount - 1 do
Strings.Add('');
// バッファを利用して読み込み #26 以降は読み込まない
Fs.Seek(0, 0);
LineCount := 0;
Str := '';
repeat
ReadCount := Fs.Read(Buffer^, BufferSize);
Buffer[ReadCount] := #0;
P := Buffer;
// バッファによって #13#10 が分断された場合のために
if P^ = #10 then Inc(P);
while not(P^ in [#0, #26]) do
begin
Start := P;
while not (P^ in [#0, #10, #13, #26]) do Inc(P);
SetString(S, Start, P - Start);
if P^ in [#0, #26] then
Str := S
else
begin
if Str <> '' then
begin
S := Str + S;
Str := '';
end;
Strings[LineCount] := S;
Inc(LineCount);
end;
if P^ = #13 then Inc(P);
if P^ = #10 then Inc(P);
end;
if P^ = #26 then Break;
until ReadCount = 0;
if Str <> '' then
Strings[LineCount] := Str;
finally
StrDispose(Buffer);
end;
finally
Fs.Free;
end;
finally
Strings.EndUpdate;
end;
end;
利用法
var
List: TStringList;
FileName: String;
begin
if OpenDialog1.Execute then
begin
FileName := OpenDialog1.FileName;
// LoadFromFile(Memo1.Lines, FileName); // なども可能
// LoadFromFile(ListBox1.Items, FileName); // 〃
List := TStringList.Create;
try
LoadFromFile(List, FileName);
// 処理
finally
List.Free;
end;
end;
end;
本田勝彦
(* サンプル蔵ログファイルからヘルプファイルが作成できます。*)
(* FDELPHI/LIB/06/114 を参照してください *)
Original document by 本田勝彦 氏 ID:(VYR01647)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|