2016-03-22 1 views
1

Ich arbeite gerade an einem Stück eines größeren Puzzles. Für mein Stück habe ich ein Dateiobjekt und das Ziel der Zip-Datei. Mir ist nie bewusst, wie groß das Dateiobjekt ist. Ich weiß nur, dass ich einen habe. Da muss der zip64 unterstützen.Wie fügen Sie Bytes über Python 2.7 in eine Datei innerhalb einer Zip-Datei an?

Mein Ziel ist es, das Dateiobjekt (Zeiger auf die Datei) zu nehmen und es in die Zip-Datei zu schreiben, ohne die gesamte Datei in den Speicher zu laden. Ich möchte das Stück für Stück machen (besonders wenn das Dateiobjekt wirklich groß ist).

Irgendwelche Ideen, wie ich das machen kann?

import zipfile 


zip_path = "/tmp/file.zip" 
file_to_zip_path = "/home/ryanb58/Desktop/movie.mp4" 

with zipfile.ZipFile(zip_path, mode="w", allowZip64=True) as zip: 
    f = open(file_to_zip_path, 'rb') 
    while True: 
     data = f.read(1024) 
     zip.writestr("file.mp4", data) 
     if not data: 
      break 

Mein Problem ist, dass, wenn ich die neuen Bytes in die Datei innerhalb der Zip schreiben. Als ich fertig bin, öffne ich den Zip und es ist nur eine riesige Liste von kleinen Dateien mit dem gleichen Namen, jede etwa 1024 Byte groß. Mein Code über ^^ Ich bin irgendwie festgefahren, also würden irgendwelche Ideen oder Lösungen groß sein.

+0

ich Sie daran zweifeln nur Bytes in einem zip in eine Datei anhängen könnte - dass Daten innerhalb der zip zusammenhängend sein, und wenn Sie versuchen, eine Datei in die Mitte anhängen, zwingen Sie necessarifly ein den gesamten Reißverschluss von diesem Punkt an neu schreiben. Sie können die Datei innerhalb der ZIP-Datei löschen und stattdessen die neue Kopie hinzufügen. –

+0

haben Sie versucht, 'zip.write (file_to_zip_path)' anstelle des gesamten 'with' Blocks zu verwenden? – jfs

+0

@MarcB Während Ihr Ansatz funktioniert, löst es nicht unbedingt mein Problem. Ich müsste immer noch wissen, wie man die Datei schreibt, ohne das Ganze in den Speicher zu bringen. – Ryanb58

Antwort

1

Nach dem Rat, den @ J.F.Sebastian in seinem Kommentar gab, konnte ich meine Datei in einen Zip schreiben, ohne die ganze Datei in den Speicher zu bringen.

Hier ist meine Lösung für die Überschreibung.

import zipfile 

BUFFER_SIZE = 1024 * 10000 # 10 megabytes. 

class Zip(zipfile.ZipFile): 

def write(self, fileobj, arcname=None, compress_type=None): 
    """Put the bytes from file into the archive under the name 
    arcname.""" 

    """CONST""" 
    ZIP64_LIMIT = (1 << 31) - 1 
    ZIP_DEFLATED = 8 

    try: 
     import zlib # We may need its compression method 
     crc32 = zlib.crc32 
    except ImportError: 
     zlib = None 
     crc32 = binascii.crc32 

    if not self.fp: 
     raise RuntimeError(
       "Attempt to write to ZIP archive that was already closed") 

    st = os.stat(fileobj.name) 
    isdir = stat.S_ISDIR(st.st_mode) 
    mtime = time.localtime(st.st_mtime) 
    date_time = mtime[0:6] 

    # Create ZipInfo instance to store file information 
    if arcname is None: 
     arcname = "/temp.zip" 
    arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) 

    # Strips any leading forward or back slashes for files. 
    while arcname[0] in (os.sep, os.altsep): 
     arcname = arcname[1:] 
    if isdir: 
     arcname += '/' 

    # Create the zipinfo. 
    zinfo = zipfile.ZipInfo(arcname, date_time) 
    zinfo.external_attr = (st.st_mode & 0xFFFF) << 16L  # Unix attributes 

    if isdir: 
     zinfo.compress_type = ZIP_STORED 
    elif compress_type is None: 
     zinfo.compress_type = self.compression 
    else: 
     zinfo.compress_type = compress_type 

    zinfo.file_size = st.st_size 
    zinfo.flag_bits = 0x00 
    zinfo.header_offset = self.fp.tell() # Start of header bytes 

    self._writecheck(zinfo) 
    self._didModify = True 

    if isdir: 
     zinfo.file_size = 0 
     zinfo.compress_size = 0 
     zinfo.CRC = 0 
     zinfo.external_attr |= 0x10 # MS-DOS directory flag 
     self.filelist.append(zinfo) 
     self.NameToInfo[zinfo.filename] = zinfo 
     self.fp.write(zinfo.FileHeader(False)) 
     return 

    # Must overwrite CRC and sizes with correct data later 
    zinfo.CRC = CRC = 0 
    zinfo.compress_size = compress_size = 0 
    # Compressed size can be larger than uncompressed size 
    zip64 = self._allowZip64 and \ 
      zinfo.file_size * 1.05 > ZIP64_LIMIT 
    self.fp.write(zinfo.FileHeader()) 
    if zinfo.compress_type == ZIP_DEFLATED: 
     cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, 
      zlib.DEFLATED, -15) 
    else: 
     cmpr = None 
    file_size = 0 
    while 1: 
     buf = fileobj.read(BUFFER_SIZE) 
     if not buf: 
      break 
     file_size = file_size + len(buf) 
     CRC = crc32(buf, CRC) & 0xffffffff 
     if cmpr: 
      buf = cmpr.compress(buf) 
      compress_size = compress_size + len(buf) 
     self.fp.write(buf) 

    if cmpr: 
     buf = cmpr.flush() 
     compress_size = compress_size + len(buf) 
     self.fp.write(buf) 
     zinfo.compress_size = compress_size 
    else: 
     zinfo.compress_size = file_size 
    zinfo.CRC = CRC 
    zinfo.file_size = file_size 
    if not zip64 and self._allowZip64: 
     if file_size > ZIP64_LIMIT: 
      raise RuntimeError('File size has increased during compressing') 
     if compress_size > ZIP64_LIMIT: 
      raise RuntimeError('Compressed size larger than uncompressed size') 
    # Seek backwards and write file header (which will now include 
    # correct CRC and file sizes) 
    position = self.fp.tell()  # Preserve current position in file 
    self.fp.seek(zinfo.header_offset, 0) 
    self.fp.write(zinfo.FileHeader()) 
    self.fp.seek(position, 0) 
    self.filelist.append(zinfo) 
    self.NameToInfo[zinfo.filename] = zinfo 

Wie Sie ich in zip64 in die FileHeader Methoden, weil auf dem System der Code ausgeführt wird, es unterstützt nur Python sehen nicht passieren können 2.7.2 Während die richtigen Header für zip64 Dateien unterstützen Sie Python benötigen 2.7.4 mindestens.

https://github.com/python/cpython/blob/2e46376c8c10908afed56ace4c7f0f7c64e80c5e/Misc/NEWS#L189