TEncodingを使うと簡単に様々な文字コードのテキストファイルを読み書きできます。
TStringListと組み合わせて使うのが一般的。
普通Delphiでテキストを入出力するって言ったらTStringListを使うわけですが、
従来の処理ではAnsiStringのデフォルトのコードページで保存されていました
上記コードであれば、"Delphi 2009欲しいなぁ"という文字列がCP932(Shift_JIS)で保存されます。
同様にLoadFromFileではCP932(Shift_JIS)で文字列が読み出されることになります。
当然ですがロケールが変わってコードページが変われば、
CP932(Shift_JIS)以外のコードページで保存されることになります。
Delphi 2009では新たにTEncodingというクラスが追加されました。
.NETをやったことがある人なら分かると思いますが、.NETのEncodingクラス(System.Text)をネイティブに移植したものです。
TStringListのLoadFromFile / SaveToFileには新たにTEncodingを引数にとる物がオーバーロードされているので、
それを使えば任意の文字コードで手軽にテキストの読み書きが可能になります。
さっきのコードとほとんど同じですが、SaveToFileメソッドの第2引数にTEncodingを指定しています。
上記例では、"Delphi 2009欲しいなぁ"という文字列がUTF-16LEで保存されます。
読み込み時にはLoadFromFileの第2引数にTEncodingを指定するだけです。
ANSIのデフォルトのコードページ(CP932:Shift_JIS)、
BOM付きのUTF-16LE/BEおよびBOM付きのUTF-8であれば、
指定を省略しても正常に読み込まれるようです。
VCLにはDialogにTOpenTextFileDialogとTSaveTextFileDialogというコンポーネントがあります。
これらは通常のOpenDialogとSaveDialogにエンコーディングのオプションを指定できるようにしたものです。
これらにはEncodingというStrings型のプロパティがあり、この中に選択させたいエンコーディングを記述します。
デフォルトでは、
・ANSI
・ASCII
・Unicode
・Big Endian Unicode
・UTF-8
・UTF-7
とリストアップされています。
適宜対応するエンコードリストに編集すればよいでしょう。
これでユーザーが指定したエンコーディングに合わせたテキストの読み書きがしやすくなりますね。
TEncodingのGetEncodingメソッドを使うと、任意のコードページの情報を取得できます。
例えば、EUC_JPで保存する場合には下記のようにします
EUC_JPのコードページは20932なので、GetEncodingの引数に指定してやるだけです。
なお、.NETにはGetEncodingの引数が文字列型のものがありますが、
TEncodingには搭載されていません。
(既にQCではリクエスト済みです)
なお、GetEncodingは内部でTMBCSEncoding.Create(CodePage)を呼び出しているだけなので、
明示的に破棄しないとメモリリークが発生します。
ちなみにUTF8プロパティなどであれば明示的に破棄する必要性はありません。
--Column:GetEncodingの仕様--
GetEncodingを使用した際に明示的にFreeしない場合、
メモリリークが発生するのは仕様です。
GetEncodingを用いた時は必ず明示的に破棄するようにしましょう。
TEncoding.GetEncodingには色々と制限があります。
基本的にGetCPInfoで情報を取れないコードページには対応できていません。
日本語を扱う上で良く出てくるコードページを以下にまとめてみました
| コードページ | 名称 | 動作 | 代替手段 |
| コードページ | 名称 | 動作 | 代替手段 |
| 0 | Default (Shift_JIS) | ○ | 不要 |
|---|---|---|---|
| 932 | Shift_JIS | ○ | 不要 |
| 1200 | UTF-16LE | × | TEncoding.Unicode TUnicodeEncoding |
| 1201 | UTF-16BE | × | TEncoding.BigEndianUnicode TBigEndianUnicodeEncoding |
| 10001 | x-mac-japanese | ○ | 不要 |
| 12000 | UTF-32LE | × | 無し |
| 12001 | UTF-32BE | × | 無し |
| 20290 | IBM EBCDIC (日本語カタカナ) | ○ | 不要 |
| 20932 | EUC_JP | ○ | 不要 |
| 50220 | iso-2022-jp (JIS) | ○ | 不要 |
| 50221 | csISO2022JP (JIS 1 バイト カタカナ可) | ○ | 不要 |
| 50222 | iso-2022-jp (JIS 1 バイト カタカナ可 - SO/SI) | ○ | 不要 |
| 51932 | EUC_JP | × | CP20932を使う |
| 65000 | UTF-7 | ○ | TEncoding.UTF7 TUTF7Encoding |
| 65001 | UTF-8 | ○ | TEncoding.UTF8 TUTF8Encoding |
動作の欄が×となっているものは、指定するとエラーが発生するものです。
このうち、黄色のものは代替手段があるもの、赤いものは代替手段がないものです。
CP51932はCP20932をもって代替しろと言うことですが、これらは厳密には少し異なります。
まぁ別の代替手段がないわけではないですが、TEncodingを用いると20932を使えということになっています。
現在のDelphi 2009には、とても残念なことにUTF32プロパティやUTF32Encodingクラスが搭載されていません。
よってUTF32LE/BEでのテキストの入出力を手軽に行えません。
これらについては将来的なアップデートで是非搭載して欲しいところです。
TEncoding.UTF8およびTUTF8EncodingはどちらもBOM付きのUTF-8として機能しているようです。
ですが、UTF-8には本来BOMは不要なものです。
BOM無しのUTF-8で保存/読み込みをするには下記のようにします。
GetEncodingを使って引数に65001を指定すると、BOM無しのUTF-8で保存されるようです。
この要領でUTF-16やUTF-32も、と行きたいところですが、
上記表にあるとおりCP1200/1201およびCP12000/12001ではGetEncodingは機能しません。
UTF-16においてBOM無しで保存をしたいと思っても、
GetEncodingではCP1200/1201には対応していないうえ、
TUnicodeEncodingおよびTBigEndianUnicodeEncodingを使うと自動的にBOMが付与されてしまいます。
最も手っ取り早い方法はTUnicodeEncodingまたはTBigEndianUnicodeEncodingを継承したクラスを作ることです。
BOMを返すメソッドがGetPreambleというメソッドなので、それをオーバーライドしてしまえばOKです。
ここでは例としてUTF-16LE用にTUnicodeEncodingを継承したTUnicodeEncodingExというクラスを作成してみました。
GetPreambleは戻り値がTBytes(Byteの動的配列)であるため、
オーバーライドしたメソッドではSetLengthで0に指定してしまえばOKです。
ちなみにTUTF8Encodingについても同様のことが言えますが、
GetEncodingと使い分ければいいだけなので、わざわざこの手法を採る必要性はありません。