2

私は非常に大きなファイル (Unicode - Delphi 2009) を解析していますが、Stackoverflow の質問で概説されているように、PChar 変数を使用して解析するための非常に効率的なルーチンがあります: Delphi で行を解析する最速の方法は何ですか?

いくつかの hex:00 文字が埋め込まれたファイルに遭遇するまで、すべてがうまく機能していました。この文字は PChar 文字列の終わりを示し、解析はその時点で停止します。

ただし、ファイルをロードすると、次のようになります。

FileStream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
Size := FileStream.Size;

次に、ファイルのサイズがはるかに大きいことがわかります。メモ帳でファイルを開くと、PChar のように最初の hex:00 で停止するのではなく、ファイルの最後まで読み込まれます。

PChar 解析を使用しながら、読み取り/解析を遅くすることなくファイルの最後まで読み取るにはどうすればよいですか?

4

3 に答える 3

2

文字に到達し#0ても、ファイル内のすべての文字を消費していない場合は、続行してください。どのように継続するかは、最初に停止することをどのように決定したかによって異なります。

あなたが参照した質問には次のコードがあります:

while (cp^ > #0) and (cp^ <= #32) do
  Inc(cp);

// using null terminator for end of file
Result := cp^ <> #0;

それは明らかにヌル文字で止まります。null 文字でファイルの終わりを示したくない場合は、null 文字で止めないでください。代わりに、すべての文字を消費した後に停止します。予想されるキャラクターの数を知り、見たキャラクターの数を追跡する必要があります。

nChars := Length(FData);
nCharsSeen := 0;
while (nCharsSeen < nChars) and (cp^ <= #32) do begin
  Inc(cp);
  Inc(nCharsSeen);
end;

// using character count for end of file
Result := nCharsSeen < nChars;

参照された回答は文字列の解析だったのでLength、文字数を学習するために使用しました。ファイルを解析している場合は、TFileStream.Size代わりに次のようなものを使用してください。

于 2012-02-11T05:51:32.060 に答える
1

以前に受け入れられた回答からコードを取得し、2 つの変数を追加してわずかに変更しました。

FPosInt: NativeUInt;
FSize: NativeUInt;

FSizeコンストラクターで文字列の長さで初期化されます (文字列変数には長さが格納されていますが、PChar には格納されていません)。 FPosIntファイル内の現在の文字の番号です。コンストラクターの追加コード:

FSize := Length(FData);
FPosInt := 0;

関数の関連部分はGetNextToken、最初の 0 バイトで停止するのではなく、文字列の最後の文字に到達するまで続きます。

// skip whitespace; this test could be converted to an unsigned int
// subtraction and compare for only a single branch
while (cp^ <= #32) and (FPosInt < FSize) do
  begin
  Inc(cp);
  Inc(FPosInt);
  end;

// end of file is reached if the position counter has reached the filesize
Result := FPosInt < FSize;

while 条件で 2 つのステートメントを切り替えました。これらは左から右に評価され、最初のステートメントはより頻繁に false と評価されるステートメントです。


別のアプローチでは、文字数をカウントしませんが、ポインターの開始位置を保存します。コンストラクターで:

FSize := Length(FData);
FStartPos := NativeUInt(FCurrPos);

そしてでGetNextToken

// skip whitespace; this test could be converted to an unsigned int
// subtraction and compare for only a single branch
while (cp^ <= #32) and ((NativeUInt(cp) - FStartPos) < FSize) do
  Inc(cp);

// end of file is reached if the position counter has reached the filesize
Result := (NativeUInt(cp) - FStartPos) < FSize;
于 2012-02-11T05:55:47.620 に答える