チケット #43 (new blog)

登録: 3 年

最終更新: 2 年

pythonでメモリ上でzipに書き込む。

報告者: mtamaki 担当者: mtamaki
優先度: major マイルストーン:
コンポーネント: blog バージョン:
キーワード: 関係者:

説明 (最終更新者: mtamaki) (diff)

7.18 zipfile -- ZIP アーカイブの処理

pythonはzipファイルの読み書きができて便利ですが、メモリ上のファイルオブジェクトをzipファイルに見立てて書き込む機能が標準になかったので書いてみました。 zipfile.ZipFile.writestrが元。

def zip_raw_write(zip_file, zinfo_or_arcname, obj):
    "base: zipfile.ZipFile.writestr"
    from zipfile import ZipInfo, ZIP_DEFLATED
    import time
    if not isinstance(zinfo_or_arcname, ZipInfo):
        zinfo = ZipInfo(filename=zinfo_or_arcname,
                        date_time=time.localtime(time.time()))
        zinfo.compress_type = zip_file.compression
    else:
        zinfo = zinfo_or_arcname
    zip_file._writecheck(zinfo)
    #オブジェクトを読み込む
    read_obj = obj.read()
    #大きさを調べてセット
    zinfo.file_size = obj.tell()            # Uncompressed size
    import binascii
    #CRCをゲット
    zinfo.CRC = binascii.crc32(read_obj)       # CRC-32 checksum
    if zinfo.compress_type == ZIP_DEFLATED:
        import zlib
        co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
             zlib.DEFLATED, -15)
        #圧縮
        read_obj = co.compress(read_obj) + co.flush()
        #圧縮後のサイズをセット
        zinfo.compress_size = len(read_obj)    # Compressed size
    else:
        zinfo.compress_size = zinfo.file_size
    zinfo.header_offset = zip_file.fp.tell()    # Start of header obj
    zip_file.fp.write(zinfo.FileHeader())
    zinfo.file_offset = zip_file.fp.tell()      # Start of file obj
    #書き込み
    zip_file.fp.write(read_obj)
    if zinfo.flag_bits & 0x08:
        # Write CRC and file sizes after the file data
        zip_file.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size,
              zinfo.file_size))
    zip_file.filelist.append(zinfo)
    zip_file.NameToInfo[zinfo.filename] = zinfo

if __name__ == '__main__':
    #zipをメモリ上でごにょごにょする
    import zipfile, StringIO
    zip_file_obj = StringIO.StringIO()
    def zip_create( path_or_obj, mode ):
        try:
            # zlib がない場合,この呼び出しは失敗して RuntimeError が返る
            return zipfile.ZipFile(path_or_obj, mode, zipfile.ZIP_DEFLATED )
        except RuntimeError:
            # ZIP_STORED (非圧縮) がデフォルトの設定
            return zipfile.ZipFile(path_or_obj, mode) #, zipfile.ZIP_STORED)
    zip_file = zip_create( zip_file_obj, "w" )
    #サンプルとしてこのコード自体をzipに突っ込むために読み込む
    script_file_obj = open( __file__, "r" )
    script_file_string = script_file_obj.read()
    script_file_obj.close()
    #名前を変えてzipに突っ込む
    zip_file.writestr( "test.py", script_file_string )
    zip_file.writestr( "test2.py", script_file_string )
    #zipを閉じる
    zip_file.close()

    #もう一個zipを用意
    zip_file_obj2 = StringIO.StringIO()
    zip_file2 = zip_create( zip_file_obj2, "w" )
    #さっきのzipをもう一個のzipに突っ込む
    zip_file_obj.seek(0,0)
    zip_raw_write( zip_file2, "test.zip", zip_file_obj )
    zip_file_obj.seek(0,0)
    zip_raw_write( zip_file2, "test2.zip", zip_file_obj )
    #zipを閉じる
    zip_file2.close()
    #ファイルに書き出す。
    import os
    real_zip_file_obj2 = open( os.path.splitext( __file__ )[0] + ".zip", "wb" )
    real_zip_file_obj2.write( zip_file_obj2.getvalue() )
    real_zip_file_obj2.close()

上記をtest.pyとして実行すると

  • test.zip
    • test.zip
      • test.py
      • test2.py
    • test2.zip
      • test.py
      • test2.py

という構造のzipができます。

(080620追記:Python2.5でzip_raw_writeがエラーになります。 PythonZipOnMemory にあるzip_raw_writeと差し替えてください。)

チケットの履歴

更新者: mtamaki (3 年 前)

  • 説明 が変更されました (diff)

更新者: mtamaki (2 年 前)

  • 説明 が変更されました (diff)

更新者: mtamaki (2 年 前)

  • 説明 が変更されました (diff)
Note: チケットについてのヘルプは TracTickets を参照 して下さい。