tarfile.open(mode='w:gz'|'w|gz'|..., fileobj=StringIO()) fails.

sebastian.noack at googlemail.com sebastian.noack at googlemail.com
Tue May 27 04:51:47 EDT 2008


I have written a FileWrapper class as workaround, which works for me
(see the code below). The FileWrapper object holds an internal file-
like object and maps its attributes, but prevents the user (in this
case tarfile) from closing the internal file, so I can still access
StringIO's content after closing the TarFile object.

But this should not be required to create in memory tar files. It is
definitely a bug, that TarFile closes external file objects passed to
tarfile.open, when closing the TarFile object. The code which opens a
file is also responsible for closing it.

Regards
Sebastian Noack


#
# File: StringIO-tarfile.py
#
#!/usr/bin/env python

from StringIO import StringIO
import tarfile
import sys

class FileWrapper(object):
	def __init__(self, fileobj):
		self.file = fileobj
		self.closed = fileobj.closed

	def __getattr__(self, name):
		# Raise AttributeError, if it isn't a file attribute.
		if name not in dir(file):
			raise AttributeError(name)

		# Get the attribute of the internal file object.
		value = getattr(self.file, name)

		# Raise a ValueError, if the attribute is callable (e.g. an instance
		# method) and the FileWrapper is closed.
		if callable(value) and self.closed:
			raise ValueError('I/O operation on closed file')
		return value

	def close(self):
		self.closed = True

def create_tar_file(filenames, fileobj, mode):
	tar_file = tarfile.open(mode=mode, fileobj=fileobj)
	for f in filenames:
		tar_file.add(f)
	tar_file.close()

if __name__ == '__main__':
	files = sys.argv[1:]
	modes = ['w%s%s' % (x, y) for x in (':', '|') for y in ('', 'gz',
'bz2')]

	for mode in modes:
		ext = mode.replace('w|', '-pipe.tar.').replace('w:',
'.tar.').rstrip('.')
		# StringIO test.
		stream = FileWrapper(StringIO())
		create_tar_file(files, stream, mode)
		fd = open('StringIO%s' % ext, 'w')
		fd.write(stream.file.getvalue())
		stream.file.close()
		fd.close()

		# file object test.
		fd = open('file%s' % ext, 'w')
		create_tar_file(files, fd, mode)



More information about the Python-list mailing list