2013-03-25 8 views
7

に含ま:読み方ファイル名は、私がGZファイルを読み込むしようとしたGZファイル

with open(os.path.join(storage_path,file), "rb") as gzipfile: 
     with gzip.GzipFile(fileobj=gzipfile) as datafile: 
      data = datafile.read() 

それは動作しますが、私は私のGZファイルに含まれるファイル名とすべてのファイルのサイズを必要とします。 このコードは、インクルードされたファイルの内容をアーカイブに出力します。

このgzファイルに含まれているファイル名はどのように読み取ることができますか?

+2

gzipでは、単一のファイルを圧縮することができます。あなたはgzipped tarアーカイブを持っていますか? –

+0

私はgzファイルを持っていますが、アーカイブに含まれているファイルとそのサイズを知る必要があります。このgzファイルには –

+0

というpcapファイルがあります –

答えて

6

Python gzipモジュールは、その情報へのアクセスを提供しません。

ソースコードは今までそれを保存することなく、それをスキップ:

if flag & FNAME: 
    # Read and discard a null-terminated string containing the filename 
    while True: 
     s = self.fileobj.read(1) 
     if not s or s=='\000': 
      break 

ファイル名のコンポーネントは、コマンドラインgzip -c減圧オプションその場合、元のファイル名のSANを.gzを使用する(存在することが保証されない、任意であり、おもう)。圧縮されていないファイルサイズはヘッダーに格納されません。代わりに最後の4バイトで見つけることができます。

ヘッダーファイルからファイル名を読み取るには、ファイルヘッダーの読み取りコードを再作成する必要があります。には、ファイル名のバイトが代わりに保持されます。

import struct 
from gzip import FEXTRA, FNAME 

def read_gzip_info(gzipfile): 
    gf = gzipfile.fileobj 
    pos = gf.tell() 

    # Read archive size 
    gf.seek(-4, 2) 
    size = struct.unpack('<I', gf.read())[0] 

    gf.seek(0) 
    magic = gf.read(2) 
    if magic != '\037\213': 
     raise IOError('Not a gzipped file') 

    method, flag, mtime = struct.unpack("<BBIxx", gf.read(8)) 

    if not flag & FNAME: 
     # Not stored in the header, use the filename sans .gz 
     gf.seek(pos) 
     fname = gzipfile.name 
     if fname.endswith('.gz'): 
      fname = fname[:-3] 
     return fname, size 

    if flag & FEXTRA: 
     # Read & discard the extra field, if present 
     gf.read(struct.unpack("<H", gf.read(2))) 

    # Read a null-terminated string containing the filename 
    fname = [] 
    while True: 
     s = gf.read(1) 
     if not s or s=='\000': 
      break 
     fname.append(s) 

    gf.seek(pos) 
    return ''.join(fname), size 

作成済みgzip.GzipFileオブジェクトと上記の関数を使用します:

filename, size = read_gzip_info(gzipfileobj) 
+0

2^32を法とする圧縮されていないファイルサイズは、「メンバ」の最後の4バイトです。 –

+0

@PavelAnossov:はい、私は今あなたの答えを見ました。 :-) –

+0

@mose up;これをPython 3互換の構文に更新しました。それについて申し訳ありません! –

3

のGzipFile自身がこの情報を持っているのではなく、次の機能が、そのプラス解凍サイズを返します。

  1. ファイル名は、アーカイブの名前から(通常は).gz
  2. 01です。
  3. 圧縮されていないファイルが4Gよりも小さい場合には、アーカイブの最後の4つのバイトは、非圧縮のサイズ含まれています(技術的には、最後の4つのバイトはの大きさ

 

In [14]: f = open('fuse-ext2-0.0.7.tar.gz') 

In [15]: f.seek(-4, 2) 

In [16]: import struct 

In [17]: r = f.read() 

In [18]: struct.unpack('<I', r)[0] 
Out[18]: 7106560 

In [19]: len(gzip.open('fuse-ext2-0.0.7.tar.gz').read()) 
Out[19]: 7106560 

を(メンバートレーラー、http://www.gzip.org/zlib/rfc-gzip.htmlでISIZEフィールド)は、元の(非圧縮)入力データモジュロ2 )

+0

実際には当てはまりません。 gzipファイルには元のファイル名を含めることができます(仕様のFNAMEフラグを参照)。 – DRayX

+0

gzipファイルはできますが、GzipFileクラスはそれを公開しません。 Martijnの答えを参照して、彼はヘッダー自身を解析する必要があります。 –

+0

私はあなたの答えを十分に慎重に読まなかったことを知っています。 gzipファイルの仕様には問題の情報がないので、私はそれを読んでいます。私は下票を謝罪します。 – DRayX

0

私はこのモードで解決しました:

fl = search_files(storage_path)  
for f in fl: 
    with open(os.path.join(storage_path,f), "rb") as gzipfile: 
     with gzip.GzipFile(fileobj=gzipfile) as datafile: 
      data = datafile.read() 
     print str(storage_path) + "/" + str(f[:-3]) + " : " + str(len(data)) + " bytes" #pcap file size 

正しいかどうかわかりません。

いずれかをお勧めしますか?

+1

それは動作しますが、明らかに圧縮解除が必要です。大きなファイルがたくさんある場合、これは遅くなることがあります。 –

+0

よろしくお願いします。今私はあなたのコードを前に投稿してみてください!ありがとう –

0

新しいコード:

fl = search_files(storage_path)  
for f in fl: 
    with open(os.path.join(storage_path,f), "rb") as gzipfile: 
     #try with module 2^32 
     gzipfile.seek(-4,2) 
     r = gzipfile.read() 
     print str(storage_path) + "/" + str(f[:-3]) + " : " + str(struct.unpack('<I' ,r)[0]) + " bytes" #dimensione del file pcap 
+0

ユーザーがgzipファイルの名前をファイル拡張子と共に変更するとどうなりますか? –

関連する問題