Тарфайл Python не создает действительный файл .tar.gz

У меня есть приложение Django, которое создает файл .tar.gz для загрузки. Локально я запускаю на своей машине разработки Python 2.7, а на удаленном сервере разработки — Python 2.6.6. Когда я загружаю файлы, я могу открывать их как через Mac Finder/командную строку, так и просматривать содержимое. Однако Python 2.7 не любит файл .tar.gz, созданный на моем удаленном сервере разработки... и мне нужно загрузить эти файлы на сайт, который использует Python для распаковки/разбора архивов. Как я могу отладить, что не так? В оболочке Python:

>>> tarfile.is_tarfile('myTestFile_remote.tar.gz')
False

>>> tarfile.is_tarfile('myTestFile_local.tar.gz')
True

>>> f = tarfile.open('myTestFile_remote.tar.gz', 'r:gz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tarfile.py", line 1678, in open
    return func(name, filemode, fileobj, **kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tarfile.py", line 1727, in gzopen
    **kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tarfile.py", line 1705, in taropen
    return cls(name, mode, fileobj, **kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tarfile.py", line 1574, in __init__
    self.firstmember = self.next()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tarfile.py", line 2331, in next
    raise ReadError(str(e))
tarfile.ReadError: invalid header

Из этого вопроса SO я также попытался запустить gzip -t для удаленного файла, но без вывода (что, я считаю, означает, что файл в порядке). Из этот другой вопрос SO я запустил file myTestFile_remote.tar.gz, и я считаю, что вывод показывает правильный формат файла:

myTestFile_remote.tar.gz: gzip compressed data, from Unix

Я не совсем уверен, что еще я могу попробовать. Похоже, исключение выбрасывается из-за того, что в моем tar-файле есть self.offset == 0, но я не знаю, что это значит, и не понимаю, как создать tar-файл, чтобы этого не произошло. Предложения приветствуются...

Не уверен, какой код будет полезен здесь. Мой код для создания и возврата tarfile:

zip_filename = '%s_%s.tar.gz' % (course.name, course.url)
s = cStringIO.StringIO()
zf = tarfile.open(zip_filename, mode='w:gz', fileobj=s)

<add a bunch of stuff>

zipped = zip_collection(zip_data)
zf.close()

if zipped:
    response = HttpResponse(content_type="application/tar")
    response['Content-Disposition'] = 'attachment; filename=%s' % zip_filename
    s.seek(0, os.SEEK_END)
    response.write(s.getvalue())

------ ОБНОВЛЕНИЕ ------ Для этот пост SO, я также проверил, что удаленный файл является файлом tar.gz, используя tar -zxvf myTestFile_remote.tar.gz из командной строки. Файл извлекается нормально.


person user    schedule 16.12.2014    source источник
comment
что вы добавляете в смолу?   -  person sax    schedule 16.12.2014
comment
Файлы изображений, документы XML, файлы HTML. И локальные, и удаленные добавляют файлы одного типа...   -  person user    schedule 16.12.2014
comment
вы закрыли tarfile?   -  person tdelaney    schedule 16.12.2014
comment
Да, извините, обновляю блок кода моего примера, чтобы показать это (пытался упростить пример кода)   -  person user    schedule 16.12.2014
comment
просто как тест, вы можете попробовать сжатие 0, чтобы увидеть, что произойдет?   -  person sax    schedule 16.12.2014
comment
Извините, просто чтобы уточнить @sax, вы имеете в виду с zf = tarfile.open(zip_filename, mode='w', fileobj=s)? Тогда загруженный файл является допустимым tarfile.   -  person user    schedule 16.12.2014
comment
Ха -- @sax, это сработало. Любая причина, по которой указание :gz приведет к неправильному кодированию файла, но без него все в порядке? Если вы что-то напишете, я буду рад принять!   -  person user    schedule 16.12.2014


Ответы (1)


Я думаю, что проблема в zlib, а не в самом tarfile.

Обходные пути:

  • создать файл, используя bz2
    tarfile.open(zip_filename, mode='w:bz2', fileobj=s)

  • форсировать уровень сжатия (как запись, так и чтение)

    zf = tarfile.open(zip_filename, mode='w:gz', fileobj=s, compresslevel=9)

    zf = tarfile.open(zip_filename, mode='r:gz', compresslevel=9)

  • более низкий уровень сжатия, пока проблема не исчезнет

    zf = tarfile.open(zip_filename, mode='w:gz', fileobj=s, compresslevel=[9-0])

  • полностью убрать компрессию

    tarfile.open(zip_filename, mode='w', fileobj=s)

последний только в том случае, если сжатие абсолютно необходимо и ни один из предыдущих не работает:

f = open(zip_filename, "w") 
proc = subprocess.Popen(["gzip", "-9"], stdin=subprocess.PIPE, stdout=fobj) 
tar = tarfile.open(fileobj=proc.stdin, mode="w|") 
tar.add(...) 
tar.close() 
proc.stdin.close() 
f.close() 
person sax    schedule 16.12.2014