13257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielr"""File-like objects that read from or write to a string buffer. 23257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 33257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielThis implements (nearly) all stdio methods. 43257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 53257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf = StringIO() # ready for writing 63257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf = StringIO(buf) # ready for reading 73257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.close() # explicitly release resources held 83257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielflag = f.isatty() # always false 93257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielpos = f.tell() # get current position 103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.seek(pos) # set current position 113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF 123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielbuf = f.read() # read until EOF 133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielbuf = f.read(n) # read up to n bytes 143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielbuf = f.readline() # read until end of line ('\n') or EOF 153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniellist = f.readlines()# list of f.readline() results until EOF 163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.truncate([size]) # truncate file at to at most size (default: current pos) 173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.write(buf) # write at current position 183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.writelines(list) # for line in list: f.write(line) 193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielf.getvalue() # return whole file's contents as a string 203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielNotes: 223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- Using a real file is often faster (but less convenient). 233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- There's also a much faster implementation in C, called cStringIO, but 243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel it's not subclassable. 253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- fileno() is left unimplemented so that code which uses it triggers 263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel an exception early. 273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- Seeking far beyond EOF and then writing will insert real null 283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel bytes that occupy space in the buffer. 293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel- There's a simple test set (see end of this file). 303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel""" 313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieltry: 323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel from errno import EINVAL 333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielexcept ImportError: 343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel EINVAL = 22 353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__all__ = ["StringIO"] 373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef _complain_ifclosed(closed): 393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if closed: 403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise ValueError, "I/O operation on closed file" 413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass StringIO: 433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """class StringIO([buffer]) 443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel When a StringIO object is created, it can be initialized to an existing 463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel string by passing the string to the constructor. If no string is given, 473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel the StringIO will start empty. 483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The StringIO object can accept either Unicode or 8-bit strings, but 503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel mixing the two may take some care. If both are used, 8-bit strings that 513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel cannot be interpreted as 7-bit ASCII (that use the 8th bit) will cause 523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel a UnicodeError to be raised when getvalue() is called. 533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __init__(self, buf = ''): 553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Force self.buf to be a string or unicode 563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not isinstance(buf, basestring): 573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel buf = str(buf) 583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf = buf 593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.len = len(buf) 603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [] 613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = 0 623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.closed = False 633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.softspace = 0 643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def __iter__(self): 663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self 673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def next(self): 693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """A file object is its own iterator, for example iter(f) returns f 703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (unless f is closed). When a file is used as an iterator, typically 713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel in a for loop (for example, for line in f: print line), the next() 723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel method is called repeatedly. This method returns the next input line, 733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel or raises StopIteration when EOF is hit. 743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel r = self.readline() 773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not r: 783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise StopIteration 793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return r 803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def close(self): 823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Free the memory buffer. 833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not self.closed: 853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.closed = True 863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel del self.buf, self.pos 873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def isatty(self): 893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Returns False because StringIO objects are not connected to a 903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel tty-like device. 913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return False 943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def seek(self, pos, mode = 0): 963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Set the file's current position. 973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The mode argument is optional and defaults to 0 (absolute file 993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel positioning); other values are 1 (seek relative to the current 1003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel position) and 2 (seek relative to the file's end). 1013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel There is no return value. 1033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 1053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.buflist: 1063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf += ''.join(self.buflist) 1073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [] 1083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if mode == 1: 1093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel pos += self.pos 1103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel elif mode == 2: 1113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel pos += self.len 1123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = max(0, pos) 1133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def tell(self): 1153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Return the file's current position.""" 1163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 1173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.pos 1183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def read(self, n = -1): 1203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Read at most size bytes from the file 1213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (less if the read hits EOF before obtaining size bytes). 1223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel If the size argument is negative or omitted, read all data until EOF 1243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel is reached. The bytes are returned as a string object. An empty 1253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel string is returned when EOF is encountered immediately. 1263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 1283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.buflist: 1293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf += ''.join(self.buflist) 1303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [] 1313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if n is None or n < 0: 1323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = self.len 1333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 1343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = min(self.pos+n, self.len) 1353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel r = self.buf[self.pos:newpos] 1363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = newpos 1373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return r 1383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def readline(self, length=None): 1403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel r"""Read one entire line from the file. 1413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel A trailing newline character is kept in the string (but may be absent 1433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel when a file ends with an incomplete line). If the size argument is 1443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel present and non-negative, it is a maximum byte count (including the 1453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel trailing newline) and an incomplete line may be returned. 1463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel An empty string is returned only when EOF is encountered immediately. 1483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Note: Unlike stdio's fgets(), the returned string contains null 1503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel characters ('\0') if they occurred in the input. 1513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 1533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.buflist: 1543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf += ''.join(self.buflist) 1553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [] 1563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel i = self.buf.find('\n', self.pos) 1573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if i < 0: 1583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = self.len 1593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 1603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = i+1 1613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if length is not None and length >= 0: 1623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.pos + length < newpos: 1633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = self.pos + length 1643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel r = self.buf[self.pos:newpos] 1653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = newpos 1663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return r 1673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def readlines(self, sizehint = 0): 1693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Read until EOF using readline() and return a list containing the 1703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel lines thus read. 1713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel If the optional sizehint argument is present, instead of reading up 1733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to EOF, whole lines totalling approximately sizehint bytes (or more 1743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to accommodate a final whole line). 1753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel total = 0 1773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel lines = [] 1783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line = self.readline() 1793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel while line: 1803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel lines.append(line) 1813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel total += len(line) 1823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if 0 < sizehint <= total: 1833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel break 1843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line = self.readline() 1853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return lines 1863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def truncate(self, size=None): 1883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Truncate the file's size. 1893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel If the optional size argument is present, the file is truncated to 1913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (at most) that size. The size defaults to the current position. 1923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The current file position is not changed unless the position 1933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel is beyond the new file size. 1943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel If the specified size exceeds the file's current size, the 1963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel file remains unchanged. 1973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 1993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if size is None: 2003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel size = self.pos 2013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel elif size < 0: 2023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise IOError(EINVAL, "Negative size not allowed") 2033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel elif size < self.pos: 2043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = size 2053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf = self.getvalue()[:size] 2063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.len = size 2073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def write(self, s): 2093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Write a string to the file. 2103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel There is no return value. 2123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 2143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not s: return 2153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Force s to be a string or unicode 2163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not isinstance(s, basestring): 2173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel s = str(s) 2183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel spos = self.pos 2193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel slen = self.len 2203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if spos == slen: 2213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist.append(s) 2223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.len = self.pos = spos + len(s) 2233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return 2243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if spos > slen: 2253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist.append('\0'*(spos - slen)) 2263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel slen = spos 2273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel newpos = spos + len(s) 2283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if spos < slen: 2293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.buflist: 2303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf += ''.join(self.buflist) 2313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [self.buf[:spos], s, self.buf[newpos:]] 2323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf = '' 2333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if newpos > slen: 2343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel slen = newpos 2353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist.append(s) 2373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel slen = newpos 2383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.len = slen 2393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.pos = newpos 2403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def writelines(self, iterable): 2423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Write a sequence of strings to the file. The sequence can be any 2433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel iterable object producing strings, typically a list of strings. There 2443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel is no return value. 2453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (The name is intended to match readlines(); writelines() does not add 2473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line separators.) 2483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel write = self.write 2503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for line in iterable: 2513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel write(line) 2523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def flush(self): 2543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Flush the internal buffer 2553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 2573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def getvalue(self): 2593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Retrieve the entire contents of the "file" at any time before 2613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel the StringIO object's close() method is called. 2623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The StringIO object can accept either Unicode or 8-bit strings, 2643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel but mixing the two may take some care. If both are used, 8-bit 2653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel strings that cannot be interpreted as 7-bit ASCII (that use the 2663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 8th bit) will cause a UnicodeError to be raised when getvalue() 2673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel is called. 2683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel _complain_ifclosed(self.closed) 2703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if self.buflist: 2713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buf += ''.join(self.buflist) 2723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.buflist = [] 2733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.buf 2743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# A little test suite 2773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef test(): 2793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel import sys 2803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if sys.argv[1:]: 2813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel file = sys.argv[1] 2823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel file = '/etc/passwd' 2843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel lines = open(file, 'r').readlines() 2853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel text = open(file, 'r').read() 2863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = StringIO() 2873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for line in lines[:-2]: 2883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write(line) 2893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.writelines(lines[-2:]) 2903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if f.getvalue() != text: 2913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise RuntimeError, 'write failed' 2923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel length = f.tell() 2933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'File length =', length 2943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(len(lines[0])) 2953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write(lines[1]) 2963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(0) 2973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'First line =', repr(f.readline()) 2983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'Position =', f.tell() 2993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line = f.readline() 3003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'Second line =', repr(line) 3013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(-len(line), 1) 3023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line2 = f.read(len(line)) 3033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if line != line2: 3043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise RuntimeError, 'bad result after seek back' 3053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(len(line2), 1) 3063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel list = f.readlines() 3073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line = list[-1] 3083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(f.tell() - len(line)) 3093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel line2 = f.read() 3103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if line != line2: 3113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise RuntimeError, 'bad result after seek back from EOF' 3123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'Read', len(list), 'more lines' 3133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'File length =', f.tell() 3143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if f.tell() != length: 3153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise RuntimeError, 'bad length' 3163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.truncate(length/2) 3173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(0, 2) 3183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel print 'Truncated length =', f.tell() 3193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if f.tell() != length/2: 3203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise RuntimeError, 'truncate did not adjust length' 3213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.close() 3223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 3233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielif __name__ == '__main__': 3243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel test() 325