複数のファイルを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をファイル分作成して一行ごとに追加していっているのですが
それですと、メモリの問題があって作成できないことがあります。
良きアドバイスをお願いします。
サンプルを見る限り、読み込むファイルは、
1行が17桁の固定長のデータと思われますが、
そうですか。
一つのファイルの行数は固定ですか。また、何行ぐらいありますか。
1000件くらいのファイルを一つのファイルにまとめるのですか。
出力するファイルは、1行が1ファイルと言うことですか。
固定行なら、1ファイルごとに、TMemoryStream に一気に読み込んで、
TMemoryStream から、17桁+2桁(改行コード分)読み込んで、
これを17桁+',' に変換して、もう一つの TMemoryStrem へMoveする。
これを、TFileStream へ書き込む。
あとのファイルも同様に変換して、追加書き込みする。
というのが、効率よさそうですね。
ファイル2個ぶんのメモリが確保できればいいし。
hatenaさん、ありがとうございます。
説明不足ですいません。
> 1行が17桁の固定長のデータと思われますが、
> そうですか。
実際には違いますが、固定長です。
> 一つのファイルの行数は固定ですか。また、何行ぐらいありますか。
最大で1000行です。少ない時もあります。
> 1000件くらいのファイルを一つのファイルにまとめるのですか。
数個のファイルを一つのファイルにまとめるんです。
> 固定行なら、1ファイルごとに、TMemoryStream に一気に読み込んで、
> TMemoryStream から、17桁+2桁(改行コード分)読み込んで、
> これを17桁+',' に変換して、もう一つの TMemoryStrem へMoveする。
> これを、TFileStream へ書き込む。
TMemoryStreamを使ったことがないので、簡単なサンプルなど教えていただけたら
嬉しいのですが。ヘルプを見たら出来そうです。
> というのが、効率よさそうですね。
> ファイル2個ぶんのメモリが確保できればいいし。
確かに二つで出来ますねーー;
とりありずサンプル作ってみました。
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 の倍数になってない場合はエラーになります。
例えば、最後の行に改行がなかったりするとエラーになります。
hatenaさん、レスありがとうございます。
このサンプルだと全てのファイルデータを1行に表示してしまいます。
でも、TMemoryStreamとTFileStreamの使い方がわかりました。
ありがとうございました。