Отправка нескольких.CSV-файлов.ZIP без сохранения на диске в Python
Я работаю над приложением для отчетов для моего веб-сайта на базе Django. Я хочу запустить несколько отчетов, и каждый отчет должен генерировать a .csv-файл в памяти, который можно загрузить в пакетном виде .застежка-молния. Я хотел бы сделать это без сохранения каких-либо файлов на диске. До сих пор, чтобы генерировать один .CSV-файл, я после операции:
mem_file = StringIO.StringIO()
writer = csv.writer(mem_file)
writer.writerow(["My content", my_value])
mem_file.seek(0)
response = HttpResponse(mem_file, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=my_file.csv'
Это прекрасно работает, но только для одного, расстегнутого .csv. Если бы у меня был, например, список .csv файлы, созданные с помощью StringIO поток:
firstFile = StringIO.StringIO()
# write some data to the file
secondFile = StringIO.StringIO()
# write some data to the file
thirdFile = StringIO.StringIO()
# write some data to the file
myFiles = [firstFile, secondFile, thirdFile]
Как я могу вернуть сжатый файл, который содержит все объекты в myFiles
и может быть правильно распакован, чтобы показать три .файлы csv?
3 ответа:
Zipfile - это стандартный библиотечный модуль, который делает именно то, что вы ищете. Для вашего случая использования, мясо и картофель-это метод под названием "writestr", который принимает имя файла и содержащиеся в нем данные, которые вы хотели бы заархивировать.
В приведенном ниже коде я использовал последовательную схему именования файлов, когда они распаковываются, но это может быть переключено на все, что вы хотите.
import zipfile import StringIO zipped_file = StringIO.StringIO() with zipfile.ZipFile(zipped_file, 'w') as zip: for i, file in enumerate(files): file.seek(0) zip.writestr("{}.csv".format(i), file.read()) zipped_file.seek(0)
Если вы хотите, чтобы ваш код был защищен в будущем (hint hint Python 3 hint hint), вы возможно, вы захотите переключиться на использование ввода-вывода.BytesIO вместо StringIO, так как Python 3-это все о байтах. Еще один бонус заключается в том, что явные запросы не нужны с io.BytesIO перед чтением (я не проверял это поведение с помощью HttpResponse от Django, поэтому я оставил этот последний поиск там на всякий случай).
import io import zipfile zipped_file = io.BytesIO() with zipfile.ZipFile(zipped_file, 'w') as f: for i, file in enumerate(files): f.writestr("{}.csv".format(i), file.getvalue()) zipped_file.seek(0)
stdlib
поставляется с модулемzipfile
, а основной классZipFile
принимает файл или файлоподобный объект:from zipfile import ZipFile temp_file = StringIO.StringIO() zipped = ZipFile(temp_file, 'w') # create temp csv_files = [(name1, data1), (name2, data2), ... ] for name, data in csv_files: data.seek(0) zipped.writestr(name, data.read()) zipped.close() temp_file.seek(0) # etc. etc.
Я не являюсь пользователем
StringIO
, поэтому у меня могут бытьseek
иread
неуместные, но, надеюсь, вы понимаете идею.
def zipFiles(files): outfile = StringIO() # io.BytesIO() for python 3 with zipfile.ZipFile(outfile, 'w') as zf: for n, f in enumarate(files): zf.writestr("{}.csv".format(n), f.getvalue()) return outfile.getvalue() zipped_file = zip_files(myfiles) response = HttpResponse(zipped_file, content_type='application/octet-stream') response['Content-Disposition'] = 'attachment; filename=my_file.zip'
StringIO имеет метод
getvalue
, который возвращает все содержимое. Вы можете сжать файл zipfile поzipfile.ZipFile(outfile, 'w', zipfile.ZIP_DEFLATED)
. Значение сжатия по умолчанию -ZIP_STORED
, которое создаст zip-файл без сжатия.