複数のファイルをcsv形式で結合

解決


aiko  2002-10-10 01:23:55  No: 1660

複数のファイルをcsv形式で保存したいのですが、
効率のいいやり方を教えて下さい。

各ファイルには
-12.3456,+78.0123
...
+11.1111,+22.1111

と1000件くらいあります。
そのファイルを各行ごとに後ろに追加していきます。
ファイル1          ファイル2
-12.3456,+78.0123,+44.4444,+55.8888
...               ...
+11.1111,+22.1111,+12.4579,-98.2154

TStringListをファイル分作成して一行ごとに追加していっているのですが
それですと、メモリの問題があって作成できないことがあります。

良きアドバイスをお願いします。


hatena  2002-10-10 03:08:07  No: 1661

サンプルを見る限り、読み込むファイルは、
1行が17桁の固定長のデータと思われますが、
そうですか。

一つのファイルの行数は固定ですか。また、何行ぐらいありますか。

1000件くらいのファイルを一つのファイルにまとめるのですか。

出力するファイルは、1行が1ファイルと言うことですか。

固定行なら、1ファイルごとに、TMemoryStream に一気に読み込んで、
TMemoryStream から、17桁+2桁(改行コード分)読み込んで、
これを17桁+',' に変換して、もう一つの TMemoryStrem へMoveする。

これを、TFileStream へ書き込む。

あとのファイルも同様に変換して、追加書き込みする。

というのが、効率よさそうですね。
ファイル2個ぶんのメモリが確保できればいいし。


aiko  2002-10-10 03:24:13  No: 1662

hatenaさん、ありがとうございます。

説明不足ですいません。
> 1行が17桁の固定長のデータと思われますが、
> そうですか。
実際には違いますが、固定長です。

> 一つのファイルの行数は固定ですか。また、何行ぐらいありますか。
最大で1000行です。少ない時もあります。

> 1000件くらいのファイルを一つのファイルにまとめるのですか。
数個のファイルを一つのファイルにまとめるんです。

> 固定行なら、1ファイルごとに、TMemoryStream に一気に読み込んで、
> TMemoryStream から、17桁+2桁(改行コード分)読み込んで、
> これを17桁+',' に変換して、もう一つの TMemoryStrem へMoveする。
> これを、TFileStream へ書き込む。

TMemoryStreamを使ったことがないので、簡単なサンプルなど教えていただけたら
嬉しいのですが。ヘルプを見たら出来そうです。

> というのが、効率よさそうですね。
> ファイル2個ぶんのメモリが確保できればいいし。
確かに二つで出来ますねーー;


hatena  2002-10-10 18:16:53  No: 1663

とりありずサンプル作ってみました。

procedure FilesToFile(FileNames: array of String; OutPutFile: String);
const
  SizeOfRow = 19; //1行の長さ(改行コード含む)
var
  Ms1, Ms2: TMemoryStream;
  Buf: Array[1..SizeOfRow] of Char;
  Fs: TFileStream;
  i, j, RowCount: integer;
begin
  Ms1 := TMemoryStream.Create;
  Ms2 := TMemoryStream.Create;
  Fs := TFileStream.Create(OutPutFile, fmCreate or fmShareExclusive);
  try
    for i := 0 to High(FileNames) do
    begin
      Ms1.LoadFromFile(FileNames[i]);
      Ms1.Position := 0;
      RowCount := Ms1.Size div SizeOfRow;
      Ms2.Size := Ms1.Size - RowCount;
      for j := 0 to RowCount - 1 do
      begin
        Ms1.ReadBuffer(Buf[1], SizeOfRow);
        Buf[SizeOfRow-1] := ',';
        Ms2.WriteBuffer(Buf[1], SizeOfRow-1);
      end;
      Ms2.Position := 0;
      Fs.CopyFrom(Ms2, Ms2.Size);
      Ms2.Position := 0;
    end;
  finally
    Ms1.Free;
    Ms2.Free;
    Fs.Free;
  end;
end;

使い方は、

procedure TForm1.Button1Click(Sender: TObject);
begin
  FilesToFile(['F1.txt','F2.txt','F3.txt'], 'OutPut.txt');
end;

これで、'F1.txt'〜'F3.txt' を、一つの CSV にまとめて
OutPut.txtに出力します。
配列でファイル名を渡すこともOKです。

エラーチェック等はしてないので、ファイルサイズが、
SizeOfRow の倍数になってない場合はエラーになります。
例えば、最後の行に改行がなかったりするとエラーになります。


aiko  2002-10-10 19:40:19  No: 1664

hatenaさん、レスありがとうございます。

このサンプルだと全てのファイルデータを1行に表示してしまいます。
でも、TMemoryStreamとTFileStreamの使い方がわかりました。
ありがとうございました。


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








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