7

gz ファイルを読み込もうとしました:

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

動作しますが、gz ファイルに含まれるすべてのファイルのファイル名とサイズが必要です。このコードは、含まれているファイルの内容をアーカイブに出力します。

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

4

5 に答える 5

7

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

ソースコードはそれを保存せずにスキップします:

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解凍オプションは元のファイル名 sans を使用する.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)
于 2013-03-25T08:47:10.900 に答える
3

GzipFile 自体にはこの情報はありませんが、

  1. ファイル名は (通常) アーカイブの名前から拡張子を引いたものです。.gz
  2. 非圧縮ファイルが 4G より小さい場合、アーカイブの最後の 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

(技術的には、最後の 4 バイトは元の (圧縮されていない) 入力データのモジュロ 2 32のサイズです (メンバー トレーラーの ISIZE フィールド、http://www.gzip.org/zlib/rfc-gzip.html ))

于 2013-03-25T08:48:02.187 に答える
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
于 2013-03-25T09:47:15.193 に答える
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

それが正しいかどうかはわかりません。

何か提案はありますか?

于 2013-03-25T09:36:46.670 に答える
0

Martjin のソリューションは非常に優れています。Python 3.6 以降用にパッケージ化しました: https://github.com/PierreSelim/gzinfo

する必要があるpip install gzinfo

あなたのコードで

import gzinfo

info = gzinfo.read_gz_info('bar.txt.gz')

# info.name is 'foo.txt'
print(info.fname)
于 2020-09-19T17:21:54.903 に答える