2013-03-25 15 views
7

Próbowałem odczytać plik gz:Jak odczytać nazwy plików włączone do pliku gz

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

to działa, ale muszę nazwy plików i rozmiar każdego pliku uwzględnione w moim pliku gz. Ten kod wydrukuje zawartość dołączonego pliku do archiwum.

Jak mogę odczytać nazwy plików zawarte w tym pliku gz?

+2

gzip mogą tylko kompresować pojedynczy plik. Czy masz skompresowane archiwum tar? –

+0

Mam plik gz, ale muszę znać plik dołączony do archiwum i jego rozmiar –

+0

w tym pliku gz Mam plik pcap –

Odpowiedz

6

Moduł Python gzip nie zapewnia dostępu do tych informacji.

Źródłem kodu przeskakuje nad nim bez kiedykolwiek przechowywania go:

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 

Komponent Nazwa pliku jest opcjonalny, a nie gwarancją obecny (opcja dekompresja poleceń gzip -c byłoby użyć oryginalnego sans Infomacje .gz w tym przypadku, Myślę). Nieskompresowany rozmiar pliku nie jest zapisany w nagłówku; możesz go znaleźć w ostatnich czterech bajtach.

Aby samodzielnie odczytać nazwę pliku z nagłówka, należy ponownie utworzyć kod odczytywania nagłówka pliku, a zamiast tego zachować bajtów nazw plików. Poniższa funkcja zwraca, że ​​Plus zdekompresowana rozmiar:

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 

pomocą powyższej funkcji z już utworzonego gzip.GzipFile obiektu: Sam

filename, size = read_gzip_info(gzipfileobj) 
+0

Nieskompresowany rozmiar pliku modulo 2^32 to ostatnie cztery bajty "elementu". –

+0

@PavelAnossov: Tak, widzę twoją odpowiedź właśnie teraz. :-) –

+0

@moose yup; Zaktualizowałem to teraz do składni zgodnej z Python 3. Przepraszam za to! –

3

GzipFile nie ma tej informacji, ale:

  1. Nazwa pliku jest (zwykle) nazwą archiwum pomniejszoną o .gz
  2. Jeśli nieskompresowany plik jest mniejszy niż 4G, to ostatnie cztery bajty archiwum zawierają nieskompresowany rozmiar:

 

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 

(technicznie, ostatnie cztery bajty to wielkość pierwotne (nieskompresowany) dane wejściowe modulo 2 (pole ISIZE w przyczepie członkowskim http://www.gzip.org/zlib/rfc-gzip.html))

+0

To nie prawda. Plik gzip może zawierać oryginalną nazwę pliku (zobacz flagę FNAME w specyfikacji). – DRayX

+0

Plik gzip może, ale klasa GzipFile go nie ujawnia. Zobacz odpowiedź Martijna, musi sam przeanalizować nagłówek. –

+0

Rozumiem, nie przeczytałem wystarczająco dokładnie odpowiedzi; Przeczytałem to, ponieważ specyfikacja pliku gzip nie zawiera wspomnianych informacji. Przepraszam za głosowanie w dół. – DRayX

0

I został rozwiązany w tym trybie:

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 

Nie wiem, czy to prawda.

Wszelkie sugestie?

+1

To działa, ale oczywiście wymaga dekompresji. Może to spowolnić, jeśli masz dużo dużych plików. –

+0

ok, dobra obserwacja! teraz próbuję z twoim kodem wysłanym wcześniej! dzięki –

0

nowy kod:

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

co zrobić, jeśli użytkownik zmieni nazwę pliku gzip wraz z rozszerzeniem pliku? –