アプリ版:「スタンプのみでお礼する」機能のリリースについて

【PythonでZIPファイル中のZIPファイルを操作したい】

PythonでZIP内のZIPを再帰的に探して操作したいと考えています。
スクリプトを書いてみたのですが、どうもうまくいきません。
どなたかマズところをご教示いただけないでしょうか?

以下のような構造のデータファイルを用意しました。
  SampleZip1.zip
    Sample1.txt
    Sample2.txt
    SampleZip1-1.zip
      Sample1-1-1.txt
      Sample1-1-2.txt
    SampleZip1-2.zip
      Sample1-2-1.txt
      Sample1-2-2.txt

以下がテストスクリプトです。
  import zipfile
  
  def listZipFile( fileName, indent ) :
  if not zipfile.is_zipfile( fileName ) :
    print( "not zip" + indent + fileName )
  return
  
  print( "zip" + indent + fileName )
  
  zip = zipfile.ZipFile( fileName, 'r' )
  
  for f in zip.namelist():
    listZipFile( f, "¥t"+ indent )
  
  zip.close()
  
  zipFileName = 'SampleZip1.zip'
  listZipFile( zipFileName, "¥t" )

が、結果は以下の通りで、ZIPの中のZIPをZIPファイルと判定してくれないみたいです。
  >findZip.py
  zip SampleZip1.zip
  not zip SampleZip1-2.zip
  not zip Sample1.txt
  not zip Sample2.txt
  not zip SampleZip1-1.zip

ZIPファイル中のファイルに対してzipfile.ZipFile()を使うのは無理があるのかなぁ?
一時ファイルにでもいったん出さないとダメ?
などと想像しているのですが・・・

どなたかよろしくお願いいたします。

A 回答 (1件)

このサイトでは、連続する空白は1つにまとめられ、タブ文字は削られます。


Pythonではインデントが重要な役目を持っているので、全角空白を使うとか、別な文字(^だの_だの)で代りにするとしましょう。

> for f in zip.namelist():
で取り出せるfは、ZIPの中での一覧での名前です。実際にそのファイルがファイルシステム上に存在するわけではないし、その「ZIp内のファイル」にアクセスするために「ファイルのように振舞うオブジェクト」を返すわけでもありません。isZipfileで失敗するのは当然でしょう。

zipfileのマニュアルを読んでみると
read(ZIP内の名前)
でバイト列として取り出せるようなので、
fp=StringIO.StriingIO(zip.read(f))
などとファイル風オブジェクトにして
    listZipFile( fp, "¥t"+ indent )
とするのはどうでしょう。
    • good
    • 0
この回答へのお礼

kmeeさん、アドバイスありがとうございます。
おかげさまで解決しました。

以下が改造したコードです。
  import zipfile
  import io
  
  def listZipFile( file, fileName, indent ) :
    try :
      zip = zipfile.ZipFile( file, 'r' )
      print( "zip" + indent + fileName )
    except zipfile.BadZipfile :
      print( "not zip" + indent + fileName )
      return
    
    for name in zip.namelist():
      fobj = io.BytesIO( zip.read( name ) )
      listZipFile( fobj, name, "¥t"+ indent )
    
    zip.close()
  
  
  zipFileName = 'SampleZip1.zip'
  listZipFile( zipFileName, zipFileName, "¥t" )
  
「 実行結果 」
  >findZip2.py
  zip   SampleZip1.zip
  not zip     Sample2.txt
  zip       SampleZip1-1.zip
  not zip         Sample1-1-2.txt
  not zip         Sample1-1-1.txt
  zip       SampleZip1-2.zip
  not zip         Sample1-2-2.txt
  not zip         Sample1-2-1.txt
  not zip     Sample1.txt

我ながらブサイクなコードになってしまいましたが、少し紆余曲折がありました。

・cStriingIO も StriingIOもimportできず。
  ネットでVer.3系ではモジュールもクラスも変わったことを知る。

・ファイルオブジェクトに対してはzipfile.is_zipfile()がかけられないトラブル。
    TypeError: invalid file: <io.BytesIO object at 0x00C552A0>
  強引にzipfile.ZipFile()をかけ、例外が発生するか否かでZIP判定するようにした。

・BytesIOでファイルオブジェクト化したものにはname属性がなく、ファイル名が得られないトラブル。
    AttributeError: 'BytesIO' object has no attribute 'name'
  結局、メソッドに「ファイル名あるいはファイルオブジェクト」と「ファイル名」の2つのパラメタを渡すというブサイクな解決方法。


ともあれ動くようにはなったので良しとしようかと思います。
あらためてお礼申し上げます。
ありがとうございました。

お礼日時:2011/08/04 22:17

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!