# Text files with automatic (un)compression and URL access. # # Written by: Konrad Hinsen # Last revision: 2000-11-17 # import os, string, sys # Use the gzip module for Python version 1.5.2 or higher gzip = None try: _version = map(string.atoi, string.split(string.split(sys.version)[0], '.')) if _version >= [1, 5, 2]: try: import gzip except ImportError: gzip = None except: pass class TextFile: """Text files with line iteration and transparent compression TextFile instances can be used like normal file objects (i.e. by calling readline(), readlines(), and write()), but can also be used as sequences of lines in for-loops. TextFile objects also handle compression transparently. i.e. it is possible to read lines from a compressed text file as if it were not compressed. Compression is deduced from the file name suffixes '.Z' (compress/uncompress), '.gz' (gzip/gunzip), and '.bz2' (bzip2). Finally, TextFile objects accept file names that start with '~' or '~user' to indicate a home directory, as well as URLs (for reading only). Constructor: TextFile(|filename|, |mode|='"r"'), where |filename| is the name of the file (or a URL) and |mode| is one of '"r"' (read), '"w"' (write) or '"a"' (append, not supported for .Z files). """ def __init__(self, filename, mode = 'r'): if string.find(filename, ':/') > 1: # URL if mode != 'r': raise IOError, "can't write to a URL" import urllib self.file = urllib.urlopen(filename) else: filename = os.path.expanduser(filename) if mode == 'r': if not os.path.exists(filename): raise IOError, (2, 'No such file or directory: ' + filename) if filename[-2:] == '.Z': self.file = os.popen("uncompress -c " + filename, mode) elif filename[-3:] == '.gz': if gzip is None: self.file = os.popen("gunzip -c " + filename, mode) else: self.file = gzip.GzipFile(filename, 'rb') elif filename[-4:] == '.bz2': self.file = os.popen("bzip2 -dc " + filename, mode) else: try: self.file = open(filename, mode) except IOError, details: if type(details) == type(()): details = details + (filename,) raise IOError, details elif mode == 'w': if filename[-2:] == '.Z': self.file = os.popen("compress > " + filename, mode) elif filename[-3:] == '.gz': if gzip is None: self.file = os.popen("gzip > " + filename, mode) else: self.file = gzip.GzipFile(filename, 'wb') elif filename[-4:] == '.bz2': self.file = os.popen("bzip2 > " + filename, mode) else: try: self.file = open(filename, mode) except IOError, details: if type(details) == type(()): details = details + (filename,) raise IOError, details elif mode == 'a': if filename[-2:] == '.Z': raise IOError, (0, "Can't append to .Z files") elif filename[-3:] == '.gz': if gzip is None: self.file = os.popen("gzip >> " + filename, "w") else: self.file = gzip.GzipFile(filename, 'ab') else: self.file = open(filename, mode) else: raise IOError, (0, 'Illegal mode: ' + repr(mode)) def __del__(self): self.close() def __getitem__(self, item): line = self.file.readline() if not line: raise IndexError return line def readline(self): return self.file.readline() def readlines(self): return self.file.readlines() def write(self, data): self.file.write(data) def writelines(self, list): for line in list: self.file.write(line) def close(self): self.file.close() def flush(self): self.file.flush()