sci

最果て風呂

Ruby の Windows における改行コードの扱い

(前提:Sinatra を使ってブラウザ用の画像閲覧アプリを作っているお話)

ディレクトリ内で変更(追加・削除のみで修正は考えない)された画像ファイルを調べるために、Ruby で下記のようにしてファイルリストを取得してみる。

File.open("list.txt", 'w') {|file|
  Dir.glob("*.png").each do |list|
    file.puts list
  end
}

それからディレクトリに画像ファイルを追加し、上で作成したリストをリネームし、新たなリストを取得して、その差分を取ってみる。

oldfile = File.readlines("list.txt.old")
newfile = File.readlines("list.txt")
newfile - oldfile

この場合は「変更があった」(つまり newfile - oldfile != 0)と判断される。今まではこれで問題なく動作していた。

ところが、ここでファイルの変更をしていない状態で差分(つまり newfile - oldfile == 0)を取っても「変更あり」とみなされる状況になってしまった。わかっているのは、スクリプトを実行するマシンによって挙動が異なってしまうらしい、ということ。ちょっと説明が難しい。


前回の続き。
ディレクトリ内で増減した差分のファイルのみにコマンドを実行するスクリプトを使っている。ところが意図しない動作をしている事がわかった。ファイルの量が多いので、Windows ならまだしも、遅い Mac が全ファイル処理をするとなると困ったことになる。だから差分処理にしたいわけ。この問題、何が原因なのかわかるまでに相当な時間がかかりましたよ〜。

表にしてみた。

処理プラットフォーム 結果
Mac でリストを作成し Mac でリストを更新 変更なしと見做される
Mac でリストを作成し Win でリストを更新 変更なしと見做される
Win でリストを作成し Mac でリストを更新 変更ありと見做される
Win でリストを作成し Win でリストを更新 変更なしと見做される

要は Mac がセンシティブなのだった。diff のように行の順番が関係しているわけでもない。困ってしまったので irb でちまちま入力して確認してみると色々なことがわかった。

処理したいリストの例をあげておく。

photo/2012/20120101hatsumoude/img01.jpg
photo/2012/20120101hatsumoude/img02.jpg
...
photo/2012/20120104shinnenaisatsu/img01.jpg

実は readlines した時点で上のリストは文字列の配列になっおり、冒頭での差分取得は配列の比較をすることと同義なのだった。先日の kramdown を調べている時にも出てきたけど、「Win は \r\n」「Mac は \n」というファイルを生成するので、テキストとしては同じでも「要素は異なる」ということになる(改行が違うから)。

上記の表にあるように、4 通りのうち 1 通りでしか問題が生じなかったので、改行コードの差異が原因であることに気付くまで時間がかかってしまった。気付けない自分もアホなんだけど。Windows Ruby はデフォルトで改行コードの差異を無視してくれるみたい。設定があるのかどうか知らんけども(Windows 上では \r\n も \n と表示され、Mac 上では \r\n は \r\n と表示される)。

拡張子の upcase, downcase でも Windows は無視してくれるので楽なのだが、複数のマシンでひとつのディスクを管理しようとすると、汎用的なスクリプトを書くのが大変になるね。puts がいけないのかなぁ。


前回の続き。
くぱぁ〜、テキストモードとバイナリモードなんて知らんかった。やっぱり Windows ってムズイ。というか、これはかなり有名な話みたい。知らずは己のみ。

File.open("list.txt", 'wb') {|file|

ファイルを「書き込み + バイナリモード」でアクセスすれば Windows で改行を「\n」で保存してくれるようになった。これで Windows でも MacOSX でも同じファイルとみなされるので、期待したとおりの動作となった。


前回の続き。
条件分岐って難しいのね。フロチャート使ってやらなきゃダメだわ。3 つの処理があって、case ではできそうもなく、if 文だと厄介な感じ。全ての処理をなめまわしても良いのだけれど、iBook での処理が厳しいのでなるべく無駄な処理をさせたくないのだ(Windows ではあっという間に処理が終了してしまうので気づかなかった部分)。


前回の続き。
ruby スクリプトを思い出しながら修正している。print 文の「\r」って何に使うのかなぁと思っていたら、行の書き換えで使えるのね。具体的にはプログレスバーの実現に使えるという...。
因果が逆になってしまった。サムネイルを作成するファイル数が多いと、いつまで待てば良いのかわからないし、もしかしたらループってたりするかもしれないので分るようにしたかった。それで調べてみると「\r」と sprintf を使う方法が見付かった。という流れ。今までは「\r」は邪魔だったけど、便利なものだね。500 枚程の画像を新規に追加してスクリプトを走らせてみたけれど、進捗状況がわかるのは嬉しい。