IBM i とDelphi/400を利用したシステムでは、現在でもテキストやCSV形式のファイルを介して、
他システムや外部サービスとデータ連携を行っているケースが少なくありません。
シンプルで汎用性が高いことから、長年にわたり採用され続けている方式です。
一方で、Windows環境の変化や外部システムの更新、
さらにはDelphi/400のバージョンアップへの対応などをきっかけに、
既存プログラムの改修が必要になる場面も少なくありません。
従来は問題なく動作していたテキスト/CSV入出力処理が、
新しい環境では文字コードや改行コード、ファイル操作方法の違いによっては
想定通りに動作しないこともあります。
今回はこのような場面で役立つ、Delphi/400における
テキスト/CSVの入出力処理に関するテクニックをいくつか紹介します。
既存資産を活かしながら、より柔軟で保守しやすい実装を行うための参考になれば幸いです。
エンコードを指定して読み込む/保存する
TStrings(TStringListなど)を
LoadFromFileで読み込む場合およびSaveToFileで保存する際は、
Shift-JIS(ANSI)またはUTF-8のどちらで読み書きする必要がある、
といった局面が多くなっているかと思います。
LoadFromFileでテキストやCSVを読み込む場合、
エンコードを指定しなければテキストの属性から自動判定されます。
エンコードを指定して読み込む場合は、以下例のように第2引数を付けて記述します。
(※今回の手順は、Delphi/400 XE3以上で対応しています。)
(※注:指定したエンコードが合致しないと文字化けの原因になります。)
//(例)それぞれのエンコードでテキストを読み込む(sFileはファイルパス)
StringList1.LoadFromFile(sFile); // 未指定(第2引数を省略すると自動判定)
StringList1.LoadFromFile(sFile, TEncoding.ANSI); // Shift-JISで読み込む
StringList1.LoadFromFile(sFile, TEncoding.UTF8); // UTF-8(BOMあり)で読み込む
テキストファイルをTStrings.LoadFromFileで読み込んだ場合、
TStrings内で文字コードの情報をEncodingプロパティとして保持します。
サブプロパティEncodingNameで確認することも可能です。
// 読み込んだ後のエンコード名を表示する例
if (StringList1.Encoding <> nil) then
begin
ShowMessage(StringList1.Encoding.EncodingName);
end
else
begin // LoadFromFileしていない場合はnilになるので注意
ShowMessage('nil');
end;

SaveToFileでテキストやCSVを保存する場合、
先ほどのLoadFromFileでエンコード情報(Encoding)を内部保持している場合は
通常のSaveToFileを行うことで同じエンコードで保存できます。
対して、Createしたあと文字列をAddし続けただけの場合やTextを代入した場合など、
LoadFromFileしていない場合はエンコード情報(Encoding)がnilのため、
そのままSaveToFileするとShift-JISとして保存されます。
連携先の都合などでUTF8として保存する必要がある場合や、
逆に強制的にShift-JISで保存する必要がある場合は、
以下例のように第2引数を付けて記述します。
※今回の手順は、Delphi/400 XE3以上で対応しています。
※LoadFromFileでUTF-8(BOMなし)のテキストを読み込んでいた場合も、
この方法で出力するとUTF-8(BOMあり)になります。
//(例)それぞれのエンコードでテキストを出力(sFileはファイルパス)
StringList1.SaveToFile(sFile); // 未指定(第2引数を省略すると自動判定)
StringList1.SaveToFile(sFile, TEncoding.ANSI); // Shift-JISで出力
StringList1.SaveToFile(sFile, TEncoding.UTF8); // UTF-8(BOMあり)で出力
UTF-7やUTF-16など、他のエンコードで
LoadFromFile・SaveToFileする場合は、以下のページに記載の値を指定してみて下さい。
System.SysUtils.TEncoding のプロパティ – RAD Studio API Documentation
【以下は12 Athens以降でのみ対応】
UTF-8(BOMなし)で出力したい場合は、
引数のエンコード設定を別の変数で定義することで実装可能です。
※11以前のバージョンでは未対応のため、
次項「出力時に改行コードを変更する」の方法をご利用ください。
procedure TForm1.Button4Click(Sender: TObject);
var
Enc: TUTF8Encoding;
sFile: String;
begin
// エンコードを指定して保存(sFileはファイルパス)
Enc := TUTF8Encoding.Create(False); // False=BOMなし
try
StringList1.SaveToFile(sFile, Enc);
finally
Enc.Free;
end;
end;
出力時に改行コードを変更する
TStrings(TStringListなど)で複数行のデータを扱う際は、
改行コードが内部で自動的に「#13#10」として扱われます。(#$D#$A・CRLFも同義)
そのため、改行コードを「#13」もしくは「#10」としたい場合には
TStringsのSaveToFileでテキストやCSVを保存することができません。
この場合はそれぞれ、以下のようなロジックで保存します。
※以下の例では「Shift-JIS」「UTF-8(BOMなし)」「UTF-8(BOMあり)」の
3形式それぞれで保存するようになっています。
必要な箇所のみを抜粋してください。
procedure TForm1.Button2Click(Sender: TObject);
var
S: String;
sFile: String;
Bytes: TBytes;
Preamble: TBytes;
FS: TFileStream;
begin
// 改行コードを目的の文字コードに変更する
// (例では#13にしていますが、実際の値に読み替え)
// (UTF-8(BOMなし)で#13#10のまま保存する場合、この行は不要)
S := StringReplace(StringList1.Text, #13#10, #13, [rfReplaceAll]);
// Shift-JISで保存する場合
begin
// 保存ファイル名
sFile := FormatDateTime('"出力"YYYYMMDD_HHNNSS', Now) + '_ansi.txt';
// Shift-JISへ変換
Bytes := TEncoding.GetEncoding(932).GetBytes(S);
// TFileStreamを生成して出力
FS := TFileStream.Create(sFile, fmCreate);
try
FS.WriteBuffer(Bytes[0], Length(Bytes));
finally
FS.Free;
end;
end;
// UTF8 BOMなしで保存する場合
begin
// 保存ファイル名
sFile := FormatDateTime('"出力"YYYYMMDD_HHNNSS', Now) + '_utf8.txt';
// UTF-8(BOMなし)
Bytes := TEncoding.UTF8.GetBytes(S);
// TFileStreamを生成して出力
FS := TFileStream.Create(sFile, fmCreate);
try
FS.WriteBuffer(Bytes[0], Length(Bytes));
finally
FS.Free;
end;
end;
// UTF8 BOMありで保存する場合
begin
// 保存ファイル名
sFile := FormatDateTime('"出力"YYYYMMDD_HHNNSS', Now) + '_utf8bom.txt';
// UTF-8(BOMあり)
Bytes := TEncoding.UTF8.GetBytes(S);
Preamble := TEncoding.UTF8.GetPreamble;
// TFileStreamを生成して出力
FS := TFileStream.Create(sFile, fmCreate);
try
if Length(Preamble) > 0 then
FS.WriteBuffer(Preamble[0], Length(Preamble));
FS.WriteBuffer(Bytes[0], Length(Bytes));
finally
FS.Free;
end;
end;
end;