Commit 7f5736e6 by willmcgugan

Basic functionality for the Zip FS

parent 198512d2
...@@ -5,7 +5,7 @@ from fs import FS, FSError ...@@ -5,7 +5,7 @@ from fs import FS, FSError
class MultiFS(FS): class MultiFS(FS):
"""A MultiFS is a filesystem that delegates to a sequence of other filesystems. """A MultiFS is a filesystem that delegates to a sequence of other filesystems.
Operations on the MultiFS will try easy 'child' filesystem in order, until it Operations on the MultiFS will try each 'child' filesystem in order, until it
succeeds. In effect, creating a filesystem that combines the files and dirs of succeeds. In effect, creating a filesystem that combines the files and dirs of
its children. its children.
......
...@@ -2,17 +2,97 @@ ...@@ -2,17 +2,97 @@
from fs import * from fs import *
from zipfile import ZipFile from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from tempfile import NamedTemporaryFile
import tempfs
class _TempWriteFile(object):
def __init__(self, fs, filename, close_callback):
self.fs = fs
self.filename = filename
self._file = self.fs.open(filename, 'w+')
self.close_callback = close_callback
def write(self, data):
return self._file.write(data)
def tell(self):
return self._file.tell()
def close(self):
self._file.close()
self.close_callback(self.filename)
class ZipFS(FS): class ZipFS(FS):
def __init__(self, zip_file, mode="r", compression="deflated", allowZip64=False): def __init__(self, zip_file, mode="r", compression="deflated", allowZip64=False):
FS.__init__(self)
if compression == "deflated": if compression == "deflated":
compression_type = zipfile.ZIP_DEFLATED compression_type = ZIP_DEFLATED
elif compression == "stored": elif compression == "stored":
compression_type = zipfile.ZIP_STORED compression_type = ZIP_STORED
else: else:
raise ValueError("Compression should be 'deflated' (default) or 'stored'") raise ValueError("Compression should be 'deflated' (default) or 'stored'")
self.zf = ZipFile(zip_file, mode, compression_type, ) if len(mode) > 1 or mode not in "rwa":
raise ValueError("mode must be 'r', 'w' or 'a'")
self.zip_mode = mode
self.zf = ZipFile(zip_file, mode, compression_type, allowZip64)
self.temp_fs = None
if mode in 'wa':
self.temp_fs = tempfs.TempFS()
def close(self):
if self.zf is not None:
self.zf.close()
self.zf = None
def __del__(self):
self.close()
def open(self, path, mode="r", **kwargs):
path = normpath(path)
if 'r' in mode:
if self.zip_mode not in 'ra':
raise OperationFailedError("OPEN_FAILED", path=path, msg="Zip file must be opened for reading ('r') or appending ('a')")
contents = self.zf.read(path)
return StringIO(contents)
if 'w' in mode:
dirname, filename = pathsplit(path)
if dirname:
self.temp_fs.makedir(dirname, recursive=True, allow_recreate=True)
f = _TempWriteFile(self.temp_fs, path, self._on_write_close)
return f
raise ValueError("Mode must contain be 'r' or 'w'")
def _on_write_close(self, filename):
sys_path = self.temp_fs.getsyspath(filename)
self.zf.write(sys_path, filename)
if __name__ == "__main__":
def test():
zfs = ZipFS("t.zip", "w")
f = zfs.open("t.txt", 'w')
f.write("Hello, World!")
f.close()
zfs.close()
rfs = ZipFS("t.zip", 'r')
print rfs.getcontents("t.txt")
test()
#zfs.close()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment