Tcl – ファイルの入出力(5) ファイルの文字コードと改行コードについて

chanコマンドについて

Tcl8.5で入出力関係のコマンドが、chanコマンドに集約されました。

以下の表の# xxxxx のコマンドが左側のchanコマンドに追加されています。

      chan blocked    ; # fblocked
      chan close      ; # close
      chan configure  ; # fconfigure
      chan copy       ; # fcopy
      chan eof        ; # eof
      chan event      ; # fileevent
      chan flush      ; # flush
      chan gets       ; # gets
      chan names      ; # file channels
      chan puts       ; # puts
      chan read       ; # read
      chan seek       ; # seek
      chan tell       ; # tell
      chan truncate   ; # ftruncate

[非推奨]
      fblocked
      fconfigure
      fcopy
      fileevent
      file channels

非推奨になっているコマンドは今後、廃止になる可能性がある為、chanコマンドで書き換えができるよう選り分けることが勧められています。

ファイルのコピー

ファイルをコピーするプログラムを2つ紹介します。

※ファイルは前回の、str.txt を使用します。

[str.txt]

Hello! Hello!
Good morning!
Bye bye!
Have a nice day!
こんにちわ
おはようございます。
バイバイ
よい1日を!

readコマンドを使う方法

[サンプル] copy1.tcl

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# ファイルをコピーする

set fid1 [open str.txt r]
set fid2 [open str.cp1.txt w]

puts $fid2 [read -nonewline $fid1]

close $fid1
close $fid2

[実行例]

$ ls str*
str.txt

$ ./copy1.tcl
$ ls str*
str.cp1.txt  str.txt

$ cat str.cp1.txt
Hello! Hello!
Good morning!
Bye bye!
Have a nice day!
こんにちわ
おはようございます。
バイバイ
よい1日を!

fcopy(chan copy)コマンドを使う方法

[書式]

fcopy inChan outCchan ?-size size? ?-command callback?
chan copy inChan outChan ?-size size? ?-command callback?

fcopyコマンドは、inChanから別のoutChanにデータをコピーします。

-sizeを指定しない場合、コピーはファイルの最後まで行われます。-sizeに指定するサイズは、2つのチャンネルが同じエンコーディングを使用している場合、サイズはバイトで、それ以外の場合は文字数です。

-commandを指定しない場合、fcopyはコピーが完了するまでブロックされ、outChanに書き込まれたバイト数または文字数を返します。

-commandを指定すると、fcopyはバックグラウンドで動作します。この場合、即座に戻り、callbackはコピーの完了後に呼び出されます。

callbackは、outChanに書き込まれたバイト数を示す1つまたは2つの追加の引数で呼び出されます。バックグラウンド・コピー中にエラーが発生した場合、2番目の引数はエラーに関連するエラー文字列です。

-size, -commandを使用した例はここでは紹介しません。

[サンプル] copy2.tcl

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# ファイルをコピーする その2

set fid1 [open str.txt r]
set fid2 [open str.cp2.txt w]

fcopy $fid1 $fid2

close $fid1
close $fid2

[実行例]

$ ./copy2.tcl
$ ls str*
str.cp1.txt  str.cp2.txt  str.txt

$ cat str.cp2.txt
Hello! Hello!
Good morning!
Bye bye!
Have a nice day!
こんにちわ
おはようございます。
バイバイ
よい1日を!

fcopyコマンドの代わりにchanコマンドを使う場合は以下のようにします。

chan copy $fid1 $fid2

文字コードと改行コード

tclの内部では文字コードにUTF-8、改行コードはLFを採用していますが、入出力処理においての文字コードと改行コードは使用環境に自動的に合わせてくれます。

※ファイルの文字コードを自動的に変換してくれるという意味ではないです。

以下は主な環境で使われているパターンです。

Windows
文字コード:シフトJIS、改行コード:CR+LF(\r\n)
※正確には文字コード:CP932

UNIXライクなOS
文字コード:UTF-8、改行コード:LF(\n)
※古い環境では文字コード:EUCが使われている場合もあります。

Mac OS X
文字コード:UTF-8、改行コード:LF(\n)

旧Mac(OS 9 以前)
文字コード:シフトJIS、改行コード:CR(\r)
※正確には文字コード:MacJapanese

[補足]

CP932
マイクロソフトがShift_JISを独自に拡張した文字コード。よってCP932の文字コードで作成されたファイルの入出力にShift_JISを指定するとローマ数字など一部の文字で文字化けが発生します。

MacJapanese
アップルがShift_JISを独自に拡張した文字コード。よってCP932の文字コードで作成されたファイルの入出力にShift_JISを指定するとローマ数字など一部の文字で文字化けが発生します。

LF : Line Feed(改行:0x0a)
CR : Carriage Return(復帰:0x0d)

Tclで使用できる主なエンコードの名前

  iso2022-jp: JIS
  shiftjis  : SJIS
  euc-jp    : EUC
  utf-8     : Unicode(UTF-8)
  cp932     : MS-SJIS
  macJapan  : 旧MACのSJIS

Tclで使用できるエンコードの名前は以下のコマンドで確認できます。

$ tclsh
% encoding names
cp860 cp861 cp862 cp863 tis-620 cp864 cp865 cp866 gb12345 gb2312-raw cp949 cp950
cp869 dingbats ksc5601 macCentEuro cp874 macUkraine jis0201 gb2312 euc-cn 
euc-jp macThai iso8859-10 jis0208 iso2022-jp macIceland iso2022 iso8859-13
iso8859-14 jis0212 iso8859-15 cp737 iso8859-16 big5 euc-kr macRomania macTurkish
iso2022-kr gb1988 macGreek ascii cp437 macRoman iso8859-1 iso8859-2 iso8859-3 
macCroatian iso8859-4 koi8-r ebcdic iso8859-5 cp1250 macCyrillic iso8859-6 cp1251
macDingbats iso8859-7 koi8-u cp1252 iso8859-8 cp1253 iso8859-9 cp1254 cp1255 
cp850 cp1256 cp932 identity cp1257 cp852 macJapan cp1258 shiftjis utf-8 cp855 
cp936 symbol cp775 unicode cp857

Tclでは、文字コードと改行コードを使用環境に合わせてくれるので同じ環境で使用する限りは気にする必要はありませんが、他の環境へファイルを持っていったり、他の環境で使われていたファイルを読み込む場合は、文字コードを変換する必要が生じる事があります。

以下のサンプルは文字コードをUTF8→CP932に変更した新しいファイルを作るプログラムです。

[サンプル] enc.tcl

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# utf-8 -> shiftjis(cp932) へ変更してコピーする

set fid1 [open str.txt r]
set fid2 [open str.sjis.txt w]

fconfigure $fid2 -translation crlf -encoding cp932

puts $fid2 [read -nonewline $fid1]

close $fid1
close $fid2

[実行例]

$ ./enc.tcl
$ ls str*
str.cp1.txt  str.cp2.txt  str.sjis.txt  str.txt

# そのまま表示させると文字化けする。
$ cat str.sjis.txt
Hello! Hello!
Good morning!
Bye bye!
Have a nice day!
�����ɂ���
���͂悤�������܂��B
�o�C�o�C
�悢1�����I


# 改行コードがCRLFで保存されていることを確認。
$ file str.sjis.txt
str.sjis.txt: Non-ISO extended-ASCII text, with CRLF line terminators

# iconvで文字コードを変換して表示させる。
$ iconv -f CP932 -t UTF-8 str.sjis.txt
Hello! Hello!
Good morning!
Bye bye!
Have a nice day!
こんにちわ
おはようございます。
バイバイ
よい1日を!

上のサンプルでは、str.sjis.txtへ出力する際に使用する文字コードと改行コードをfconfigureコマンドで変更しています。

これも、fconfigureコマンドの代わりにchanコマンドを使う場合は以下のようにします。

chan configure $fid2 -translation crlf -encoding cp932

iconvは比較的に新しいUNIXライクなOSであれば標準でインストールされていると思います。

次回は、ファイルを開く時のエラー処理について紹介します。

コメント

タイトルとURLをコピーしました