2011-03-26

Windowsの「圧縮フォルダ」ではまる

先日公開した「Smart.fm Memento Maker」では、日記や画像のファイルをzipファイルにまとめて圧縮しているのですが、ユーザーの方から「ダウンロードしたzipファイルに何も入っていない」という報告がいくつか挙がってきました。自分の環境では(生成された)zipファイルを何事もなく展開できているので不思議に思っていたところ、どうもWindows標準の「圧縮フォルダ」でうまく扱えないということが判明しました。確かに、zipファイルをオープンしても、ファイルリストに何も表示されません。

ここで直感的に「パス区切り文字が原因に違いない」と考えました。というのも、zipファイル内の個々のファイルのパス文字列を設定する際に、ディレクトリの区切り文字として「スラッシュ(/)」を使っていたからです。コードとしては以下のような感じです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import zipfile

content = 'The quick brown fox jumps over the lazy dog.\n'
zipobj = zipfile.ZipFile('foo.zip', 'w', zipfile.ZIP_DEFLATED)
zipobj.writestr('/test.txt'.encode('utf-8'), content)
zipobj.close()

そこで、「Windowsだし、スラッシュではなくてバックスラッシュでないとだめなのでは?」と安直に考えて、パス区切り文字をバックスラッシュ('\')に変更してみました。が、やはり現象は変わらず。うーむ。

しかしその後の調査の結果、やはりパス区切り文字が原因だと判明しました。zipファイル内の個々のファイルにて、パス文字列の先頭にパス区切り文字(スラッシュ)を付けていたのですが、これを削るとWindowsの圧縮フォルダでも正常に扱えることが分かりました。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import zipfile

content = 'The quick brown fox jumps over the lazy dog.\n'
zipobj = zipfile.ZipFile('foo.zip', 'w', zipfile.ZIP_DEFLATED)
zipobj.writestr('test.txt'.encode('utf-8'), content) # 先頭のスラッシュを削ればOK
zipobj.close()

ファイルパスの先頭にスラッシュがある場合、内部では「名前が空文字列('')のディレクトリ」として扱われているのかもしれません。今になって考えると、なんで私はファイルパスの先頭にスラッシュをつけようとしたのか、ちょっと疑問に思います。

一応これで期待通りに動作できるようになったのですが、本件、ファイルパスの先頭にスラッシュを付けようとした私が悪いのか、あるいは先頭のスラッシュを扱えないWindowsの圧縮フォルダが悪いのか、どちらなのでしょうか? というわけで、ちょっとzipファイルの規格を調べたところ、以下のような記述が見つかりました。「MUST NOT」ではなくて「SHOULD NOT」ではありますが、いずれにせよ先頭のスラッシュは含まないのが無難ということでしょうかね。

file name: (Variable)
The name of the file, with optional relative path. The path stored should not contain a drive or device letter, or a leading slash. All slashes should be forward slashes '/' as opposed to backwards slashes '\' for compatibility with Amiga and UNIX file systems etc. (snip...)
http://www.pkware.com/documents/casestudies/APPNOTE.TXT
ファイル名: (可変長)
ファイルの名前(と任意の相対パス)。パス領域には、ドライブ文字・デバイス文字・先頭のスラッシュを含むべきではない。すべてのスラッシュは、AmigaやUNIX等のファイルシステムとの互換性のために、バックスラッシュ('\')ではなく、フォワードスラッシュ('/')とするべきである。(中略)

以上、備忘のため残しておきます。

0 件のコメント:

コメントを投稿