2015-11-08 9 views
3

У меня есть файл .gz, и мне нужно получить имя файла внутри него с помощью python.Как указать содержимое gz-файла без его извлечения в python?

Этот вопрос так же, как this one

Единственное отличие состоит в том, что мой файл .gz не .tar.gz поэтому tarfile библиотека не помогло мне здесь

Я использую requests библиотеку для запроса URL. Ответ представляет собой сжатый файл.

Вот код, я использую, чтобы загрузить файл

response = requests.get(line.rstrip(), stream=True) 
     if response.status_code == 200: 
      with open(str(base_output_dir)+"/"+str(current_dir)+"/"+str(count)+".gz", 'wb') as out_file: 
       shutil.copyfileobj(response.raw, out_file) 
      del response 

Этот код загружает файл с именем 1.gz, например. Теперь, если я открою файл с помощью архивного ящика, файл будет содержать что-то вроде my_latest_data.json

Мне нужно извлечь файл, а вывод будет my_latest_data.json.

Вот код, я использую, чтобы извлечь файл

inF = gzip.open(f, 'rb') 
outfilename = f.split(".")[0] 
outF = open(outfilename, 'wb') 
outF.write(inF.read()) 
inF.close() 
outF.close() 

Переменная outputfilename является строкой я обеспечиваю в сценарии, но мне нужно реальное имя файла (my_latest_data.json)

+2

Проблема заключается в том, что GZIP является * только * сжатие, не обязательно архив. Внутри не может быть манифеста внутри, чтобы даже смотреть. – zxq9

+0

Какая ошибка? Где код, который вы пробовали? Ваш вопрос непонятен. –

+0

Добавляя к тому, что @ zxq9 сказал, gzip отличается от Zip-файла (архива) тем, что он может «содержать» только один файл. Единственное, что может иметь это оригинальное имя файла. –

ответ

3

Вы можете» t, потому что Gzip не является форматом архива.

Это немного дерьма объяснения по себе, так что позвольте мне разорвать этот вниз немного больше, чем я сделал в комментарии ...

Это просто сжатие

Будучи «просто система сжатия "означает, что Gzip работает на входных байтах (обычно из файла) и выводит сжатые байты. Вы не можете знать, представляют ли байты внутри несколько файлов или только один файл - это только поток сжатых байтов. Вот почему вы можете принимать gzipped данные по сети, например. Его bytes_in -> bytes_out.

Что такое манифест?

манифест - это заголовок в архиве, который выступает в качестве оглавления для архива. Обратите внимание, что теперь я использую термин «архив», а не «сжатый поток байтов». Из архива следует, что это набор файлов или сегментов, на которые ссылается манифест - сжатый поток байтов просто поток байтов.

Что внутри Gzip, так или иначе?

Несколько упрощенное описание.Содержание GZ-файл является:

  1. Заголовок со специальным номером, чтобы указать его в GZIP, версию и метку времени (10 байт)
  2. Дополнительные заголовки; как правило, в том числе и исходное имя файла (если цель сжатия был файл)
  3. тела - некоторые сжатые данные
  4. CRC-32 контрольной суммы в конце (8 байт)

Вот и все. Нет манифеста.

Форматы архивов, с другой стороны, будут иметь манифест внутри. Вот где бы входила библиотека tar. Тар - это всего лишь способ объединить кучу бит в один файл и помещать манифест спереди, который позволяет вам узнать имена исходных файлов и какими размерами они были до объединенных в архив. Следовательно, .tar.gz является настолько распространенным явлением.

Есть утилиты, которые позволяют вам распаковывать части файла gzip за раз или декомпрессировать его только в памяти, чтобы затем вы могли исследовать манифест или что-то еще, что может быть внутри. Но детали любого манифеста специфичны для формата архива, содержащегося внутри.

Обратите внимание, что это отличается от zip. Почтовый индекс - - формат архива и как таковой содержит манифест. Gzip - это компрессия библиотека, как bzip2 и друзья.

+0

Возможно, вы захотите объяснить, что такое «манифест». Непонятно, что он описывает список файлов, содержащихся в архиве. –

+0

Как обычные диспетчеры архивов смогут показать мне файлы внутри .gz? – Fanooos

+0

@Fanooos Они заглянут внутрь gzip, чтобы узнать, содержит ли он архив или нет. Как упоминалось выше, есть утилиты, позволяющие вам манипулировать данными gzipped «на лету» (например, 'zcat' - do' man zcat', чтобы читать об этом - очень slick), поэтому он может проверять внутренние заголовки файлов таким образом без больших издержек. Вот почему так много .ps-документов в настоящее время «.ps.gz» - компромисс между временем и пространством в целом благоприятен сегодня. – zxq9

1

Как отмечалось в другом ответе, ваш вопрос может иметь смысл только, если я вынимаю множественное число: «У меня есть .gz файл, и мне нужно, чтобы получить имя файла внутри него с помощью питона.»

Заголовок gzip может содержать или не иметь имя файла в нем. Утилита gzip обычно игнорирует имя в заголовке и распаковывается в файл с тем же именем, что и файл .gz, но с разделом .gz. Например. ваш 1.gz распаковал бы файл с именем 1, даже если заголовок имеет в нем имя файла my_latest_data.json. Опция -N gzip будет использовать имя файла в заголовке (а также отметку времени в заголовке), если таковая имеется. Итак, gzip -dN 1.gz создаст файл my_latest_data.json, а не 1.

Вы можете найти имя файла в заголовке в Python, обработав заголовок вручную. Подробности можно найти в gzip specification.

  1. Проверьте, что первые три байта: 1f 8b 08.
  2. Сохранить четвертый байт. Назовите это flags. Если flags & 8 равно нулю, то сдайте - в заголовке нет имени файла.
  3. Пропустить следующие шесть байтов.
  4. Если flags & 2 не равно нулю, пропустите два байта.
  5. Если flags & 4 не равно нулю, прочитайте следующие два байта. Учитывая, что они находятся в небольшом концевом порядке, сделайте целое число из этих двух байтов, называя его xlen. Затем пропустите xlen байт.
  6. Мы уже знаем, что flags & 8 не равен нулю, поэтому вы находитесь под именем файла.Прочитайте байты, пока не получите нулевой байт. Эти байты до, но не включая нулевой байт, являются именем файла.
3

Используя советы от ответа Марка Адлера и немного осмотра на модуле gzip, я настроил эту функцию, которая извлекает внутреннее имя файла из файлов gzip. Я заметил, что объекты GzipFile есть собственный метод _read_gzip_header(), что почти получает имя файла, так что я сделал на основе этого

import gzip 

def get_gzip_filename(filepath): 
    f = gzip.open(filepath) 
    f._read_gzip_header() 
    f.fileobj.seek(0) 
    f.fileobj.read(3) 
    flag = ord(f.fileobj.read(1)) 
    mtime = gzip.read32(f.fileobj) 
    f.fileobj.read(2) 
    if flag & gzip.FEXTRA: 
     # Read & discard the extra field, if present 
     xlen = ord(f.fileobj.read(1)) 
     xlen = xlen + 256*ord(f.fileobj.read(1)) 
     f.fileobj.read(xlen) 
    filename = '' 
    if flag & gzip.FNAME: 
     while True: 
      s = f.fileobj.read(1) 
      if not s or s=='\000': 
       break 
      else: 
       filename += s 
    return filename or None 
+0

'gzip' не имеет атрибута' read32'. Я использую python 34 –

+0

Ok Спасибо, я тестировал только на python 2.7 – AndreLobato

Смежные вопросы