環境はWindowsXP Delphi6personalです。
目的は、ファイル名を検索して、フルパスをテキストで
HDDのファイルに書き込み(大抵は2〜5万件)
あとで、手動で100番目、101番目、50番目などとランダムに指定して
そこに書かれたファイル名を取得したいのです。
書き込みに関しては過去ログに「ファイルの入出力について」で見つけました。
書き込みは下記のコードでうまくいきました。
コレに対応する読む方法がうまくいきません。
var
counter:integer;
procedure TForm1.Button1Click(Sender: TObject);
var
fs:TFileStream;
fn,s:string;
begin
fn := 'c:\TestData.txt';
if FileExists(fn) then
fs := TFileStream.Create(fn,fmOpenReadWrite or fmShareDenyWrite)
else
fs := TFileStream.Create(fn,fmCreate or fmShareDenyWrite);
try
s := 'data : '+IntToStr(counter)+#13#10; // 改行を入れておく
Inc(counter);
fs.Seek(0,soFromEnd);// ファイルの末尾にシークして移動
fs.Write(PChar(s)^,Length(s)); // データを追加
finally
fs.Free;
end;
end;
説明を探して読むのですが、先頭バイトを書くとか最後のヌルを書くときは+1とか
sizeofをつかうとかLengthをつかうとか、古いコードで今はあまり使わないとか、
なんだか書く方式と読む方式が一致していないと
いけないような感じを受けて説明がよくわかりません。
この目的に合う、ランダムリードの方法を教えて頂けませんか。
(今はListboxを使っています。リソースを消費するのでやめたいです)
よろしくお願いします。
固定長レコードでない場合 Indexファイル作ったほうが無難 (DBと同じ)
procedure TForm1.Button1Click(Sender: TObject);
var
fs,fs2:TFileStream;
fn,fn2,s:string;
I64: Int64;
Size: Integer;
begin
fn := 'c:\TestData.txt';
fn2 := 'c:\TestData.idx';
if FileExists(fn) then
begin
fs := TFileStream.Create(fn,fmOpenReadWrite or fmShareDenyWrite);
fs.Seek(0,soFromEnd);// ファイルの末尾にシークして移動
end
else
begin
fs := TFileStream.Create(fn,fmCreate or fmShareDenyWrite);
end;
if FileExists(fn2) then
begin
fs2 := TFileStream.Create(fn2,fmOpenReadWrite or fmShareDenyWrite);
fs2.Seek(0,soFromEnd);// ファイルの末尾にシークして移動
end
else
begin
fs2 := TFileStream.Create(fn2,fmCreate or fmShareDenyWrite);
end;
try
s := 'data : '+IntToStr(counter);
Inc(counter);
(* Index *)
I64 := fs.Position;
fs2.Write(I64,SizeOf(I64)); //Index
(* レコード長 *)
Size := Length(S);
fs.Write(Size,SizeOf(Size));
(* データ *)
fs.Write(PChar(s)^,Length(s));
finally
fs.Free;
fs2.Free;
end;
end;
function TForm1.LoadFromFile(Index: Integer): String;
var
fs,fs2:TFileStream;
fn,fn2,s:string;
I64: Int64;
Buffer: array[0..MAX_PATH+4] of Char;
Size: Integer;
begin
Result := '';
fn := 'c:\TestData.txt';
fn2 := 'c:\TestData.idx';
fs := TFileStream.Create(fn,fmOpenRead or fmShareDenyRead);
fs2 := TFileStream.Create(fn2,fmOpenRead or fmShareDenyRead);
try
fs2.Position := Index * SizeOf(I64);
fs2.Read(I64,SizeOf(I64));
fs.Position := I64;
fs.Read(Size,SizeOf(Size));
Buffer := '';
fs.Read(Buffer,Size);
Result := StrPas(Buffer);
finally
fs.Free;
fs2.Free;
end;
end;
ファイルサイズを気にしなければ、シーク速度を稼いでランダムアクセスするためには
固定長のレコードサイズにしたらいいのでは? 最大で一レコードは MaxPath のサイズに
収まることは分かっていることだし。これなら、10000番目のデータにアクセス
するのにいくらシークしたらいいかすぐに分かりますし、高速にランダムアクセスできるはず。
KHE00221さん、うんとさん早速有り難うございました。
優しく解りやすく助かります。
うまくいきました。
また教えてください。<(_ _)>
ツイート | ![]() |