テキストファイルの一部を、高速にTMemoで表示するには?

解決


まる  2005-07-16 07:33:24  No: 16400

連続で質問しまして、すみません。
もうひとつ、質問させてください。

現在、テキストファイルを読み込み、そのファイルの一部をTMemoで表示させています。
(一部とは、先頭から○○行とかの指定した行数です)
方法は、指定行数分をループでReadlnしながらTStringListに設定します。
そして終えたらTStringListをTMemo.Lines.AddStringsで設定しています。
この方法ですと簡単にできましたが、読み込み速度が遅いようです。
(TMemo.Lines.LoadFromFileで全て読み込んだ時と比べています)

テキストファイルの先頭から一部をもっと速く取得する方法はあるのでしょうか?
よろしくお願いします。

環境:
WindowsXP HOME SP2
Delphi6 Personal


代案  2005-07-16 08:01:17  No: 16401

指定行数ではなく、指定文字数を読み込むのなら速くできるけど。


まる  2005-07-16 10:10:12  No: 16402

指定文字数でもいいです。
それはどうすればいいんですか?


メラトニン  2005-07-16 17:24:09  No: 16403

誤解だったら申し訳ないですが、質問が分かりづらいです。

AStrings : TStringList; //全テキストデータ
Memo1: TMemo; //一部を表示するTMemo

for i:=0 to 10 do
  Memo1.LInes.AddStrings(AStrings.strings[i]);
みたく、AStringsの内容をMemo1に書き込む速度が気になるのであれば

もうひとつTStringListもしくはstringバッファーを用意して
BStrings:TStringList
BStrings.clear
for i:=0 to 10 do
  BStrings.AddStrings(AStrings.strings[i]);
最後に一気にTMemoに出力すると早くなります。
Memo1.text:=BStrings.Text;


大安  2005-07-16 18:23:18  No: 16404

'_Test.txt'ファイルの先頭から300文字をMemoに表示。

procedure TForm1.Button1Click(Sender: TObject);
const
 READ_SIZE = 300;
var
 Buf: PChar;
begin
 with TFileStream.Create('_Test.txt', fmOpenRead) do begin
  Buf := nil;
  try
   GetMem(Buf, READ_SIZE+1);
   Read(Buf^, READ_SIZE);
   Buf[READ_SIZE] := #0;
   Memo1.SetTextBuf(Buf);
  finally
   if Assigned(Buf) then FreeMem(Buf);
   Free;
  end;
 end;
end;


ダイアン  2005-07-16 18:42:27  No: 16405

>  Read(Buf^, READ_SIZE);
>  Buf[READ_SIZE] := #0;
ここは、下のようにするべきだね。
   Buf[Read(Buf^, READ_SIZE)] := #0;


ほんとに?  2005-07-16 19:59:44  No: 16406

300バイトと300文字じゃ全然違うな


無問題  2005-07-16 20:16:13  No: 16407

質問者は、「ファイル先頭の一部分を読み込みたい」だけなのだから、
300バイト≠300文字であっても問題無し。


まる  2005-07-16 22:23:25  No: 16408

みなさん、ありがとうございました。
テストソースをあげておけば良かったですね。
すみませんでした。

大安さん、ダイアンさんの助言を参考に、指定バイト数読みの方法を
作成中のプログラムに取り込んでみたところ、修正前よりかなり速いです。
指定バイト数 = (指定行数 * 80) + (指定行数 * 2) で行っていますので、
  ※(指定行数 * 80)…1行を80バイトしての指定行数分のバイト
  ※(指定行数 * 2))…改行コード?とかの指定行数分のバイト
単純に指定行数による1行読み込みよりは確実に速いはずです。
(結果、今の方が読み込む行数が多いだろうから)

大変助かりました。
ありがとうございました。

いまさらですが、テストしてみたソース(一気読み、指定行数読み、指定バイト数読み)を
あげておきます。

ソース:
unit Unit1;

interface

uses
  DateUtils,
  Unit_LogManager,
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;

    Memo2: TMemo;
    Button2: TButton;

    Memo3: TMemo;
    Button3: TButton;

    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);

  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  FilePath: String;

procedure TForm1.Button1Click(Sender: TObject);
var
  StartDateTime: TDateTime;
  EndDateTime: TDateTime;

  StartString: String;
  EndString: String;

begin
            //TMemoで一気に全てテキストファイルを読み込む

            StartDateTime := Now;
            StartString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', StartDateTime);

            Memo1.Lines.LoadFromFile(FilePath);

            EndDateTime := Now;
            EndString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', EndDateTime);

            ShowMessage(StartString + #13 +
                        EndString + #13 +
                        '差:' + IntToStr(MilliSecondsBetween(EndDateTime, StartDateTime)));

end;

procedure TForm1.Button2Click(Sender: TObject);
const
 READ_SIZE = 300;  //指定行数:300行

var
  ReadTextFile: TextFile;
  LineString: String;
  LineCount: Integer;
  MemoStringList: TStringList;

  StartDateTime: TDateTime;
  EndDateTime: TDateTime;

  StartString: String;
  EndString: String;

begin
            //指定行数を1行ずつテキストファイルから読み込む

            StartDateTime := Now;
            StartString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', StartDateTime);

            //初期処理
            LineCount := 0;
            MemoStringList := TStringList.Create;

            AssignFile(ReadTextFile, FilePath);
            Reset(ReadTextFile);

            if not Eof(ReadTextFile) then
              LineCount := LineCount + 1;

            while (not Eof(ReadTextFile)) and (LineCount <= READ_SIZE) do
            begin
              Readln(ReadTextFile, LineString);
              MemoStringList.Add(LineString);

              LineCount := LineCount + 1;
            end;

            Memo2.Lines.AddStrings(MemoStringList);
            //後処理
            CloseFile(ReadTextFile);
            MemoStringList.Free;

            EndDateTime := Now;
            EndString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', EndDateTime);

            ShowMessage(StartString + #13 +
                        EndString + #13 +
                        '差:' + IntToStr(MilliSecondsBetween(EndDateTime, StartDateTime)));

end;

procedure TForm1.Button3Click(Sender: TObject);
const
 READ_SIZE = 300 * 80 + 600;  //指定バイト数:300行 * 80 + 600
                              // (1行を80バイトとしての300行分のバイト数 + 
                              //  300行分の改行文字のバイト数)

var
  Buf: PChar;

  StartDateTime: TDateTime;
  EndDateTime: TDateTime;

  StartString: String;
  EndString: String;

begin
            //指定バイト数をテキストファイルから読み込む

            StartDateTime := Now;
            StartString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', StartDateTime);

            with TFileStream.Create(FilePath, fmOpenRead) do begin
              Buf := nil;
              try
                GetMem(Buf, READ_SIZE + 1);
                Buf[Read(Buf^, READ_SIZE)] := #0;
                Memo3.SetTextBuf(Buf);
              finally
                if Assigned(Buf) then FreeMem(Buf);
                Free;
              end;
            end;

            EndDateTime := Now;
            EndString := FormatDateTime('yyyy/mm/dd hh:mm:ss.zzz', EndDateTime);

            ShowMessage(StartString + #13 +
                        EndString + #13 +
                        '差:' + IntToStr(MilliSecondsBetween(EndDateTime, StartDateTime)));

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Clear;
  Memo2.Clear;
  Memo3.Clear;

  FilePath := 'C:\TEST\ファイルサンプル.txt';

end;

end.


にしの  2005-07-16 22:41:55  No: 16409

1行ずつ追加する場合は、追加し始める前に
Memo1.Lines.BeginUpdate;
全て追加し終えた後に、
Memo1.Lines.EndUpdate;
をすると、少し早くなると思います。


いやいや  2005-07-17 03:40:08  No: 16410

> 300バイト≠300文字であっても問題無し。

そうかもしれないが、300文字とかいってるから期待してたのに期待はずれ


まる  2005-07-17 19:00:53  No: 16411

>>にしの さん
ありがとうございます。参考になります。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加