GIF89a;
Mass Deface = 0: if self.pos + length < newpos: newpos = self.pos + length r = self.buf[self.pos:newpos] self.pos = newpos return r def readlines(self, sizehint = 0): """Read until EOF using readline() and return a list containing the lines thus read. If the optional sizehint argument is present, instead of reading up to EOF, whole lines totalling approximately sizehint bytes (or more to accommodate a final whole line). """ total = 0 lines = [] line = self.readline() while line: lines.append(line) total += len(line) if 0 < sizehint <= total: break line = self.readline() return lines def truncate(self, size=None): """Truncate the file's size. If the optional size argument is present, the file is truncated to (at most) that size. The size defaults to the current position. The current file position is not changed unless the position is beyond the new file size. If the specified size exceeds the file's current size, the file remains unchanged. """ _complain_ifclosed(self.closed) if size is None: size = self.pos elif size < 0: raise IOError(EINVAL, "Negative size not allowed") elif size < self.pos: self.pos = size self.buf = self.getvalue()[:size] self.len = size def write(self, s): """Write a string to the file. There is no return value. """ _complain_ifclosed(self.closed) if not s: return # Force s to be a string or unicode if not isinstance(s, basestring): s = str(s) spos = self.pos slen = self.len if spos == slen: self.buflist.append(s) self.len = self.pos = spos + len(s) return if spos > slen: self.buflist.append('\0'*(spos - slen)) slen = spos newpos = spos + len(s) if spos < slen: if self.buflist: self.buf += ''.join(self.buflist) self.buflist = [self.buf[:spos], s, self.buf[newpos:]] self.buf = '' if newpos > slen: slen = newpos else: self.buflist.append(s) slen = newpos self.len = slen self.pos = newpos def writelines(self, iterable): """Write a sequence of strings to the file. The sequence can be any iterable object producing strings, typically a list of strings. There is no return value. (The name is intended to match readlines(); writelines() does not add line separators.) """ write = self.write for line in iterable: write(line) def flush(self): """Flush the internal buffer """ _complain_ifclosed(self.closed) def getvalue(self): """ Retrieve the entire contents of the "file" at any time before the StringIO object's close() method is called. The StringIO object can accept either Unicode or 8-bit strings, but mixing the two may take some care. If both are used, 8-bit strings that cannot be interpreted as 7-bit ASCII (that use the 8th bit) will cause a UnicodeError to be raised when getvalue() is called. """ _complain_ifclosed(self.closed) if self.buflist: self.buf += ''.join(self.buflist) self.buflist = [] return self.buf # A little test suite def test(): import sys if sys.argv[1:]: file = sys.argv[1] else: file = '/etc/passwd' lines = open(file, 'r').readlines() text = open(file, 'r').read() f = StringIO() for line in lines[:-2]: f.write(line) f.writelines(lines[-2:]) if f.getvalue() != text: raise RuntimeError, 'write failed' length = f.tell() print 'File length =', length f.seek(len(lines[0])) f.write(lines[1]) f.seek(0) print 'First line =', repr(f.readline()) print 'Position =', f.tell() line = f.readline() print 'Second line =', repr(line) f.seek(-len(line), 1) line2 = f.read(len(line)) if line != line2: raise RuntimeError, 'bad result after seek back' f.seek(len(line2), 1) list = f.readlines() line = list[-1] f.seek(f.tell() - len(line)) line2 = f.read() if line != line2: raise RuntimeError, 'bad result after seek back from EOF' print 'Read', len(list), 'more lines' print 'File length =', f.tell() if f.tell() != length: raise RuntimeError, 'bad length' f.truncate(length/2) f.seek(0, 2) print 'Truncated length =', f.tell() if f.tell() != length/2: raise RuntimeError, 'truncate did not adjust length' f.close() if __name__ == '__main__': test()