1 """File-like objects that read from or write to a string buffer.
3 This implements (nearly) all stdio methods.
5 f = StringIO() # ready for writing
6 f = StringIO(buf) # ready for reading
7 f.close() # explicitly release resources held
8 flag = f.isatty() # always false
9 pos = f.tell() # get current position
10 f.seek(pos) # set current position
11 f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
12 buf = f.read() # read until EOF
13 buf = f.read(n) # read up to n bytes
14 buf = f.readline() # read until end of line ('\n') or EOF
15 list = f.readlines()# list of f.readline() results until EOF
16 f.truncate([size]) # truncate file at to at most size (default: current pos)
17 f.write(buf) # write at current position
18 f.writelines(list) # for line in list: f.write(line)
19 f.getvalue() # return whole file's contents as a string
22 - Using a real file is often faster (but less convenient).
23 - There's also a much faster implementation in C, called cStringIO, but
24 it's not subclassable.
25 - fileno() is left unimplemented so that code which uses it triggers
27 - Seeking far beyond EOF and then writing will insert real null
28 bytes that occupy space in the buffer.
29 - There's a simple test set (see end of this file).
32 from errno
import EINVAL
36 __all__
= ["StringIO"]
39 """class StringIO([buffer])
41 When a StringIO object is created, it can be initialized to an existing
42 string by passing the string to the constructor. If no string is given,
43 the StringIO will start empty.
45 The StringIO object can accept either Unicode or 8-bit strings, but
46 mixing the two may take some care. If both are used, 8-bit strings that
47 cannot be interpreted as 7-bit ASCII (that use the 8th bit) will cause
48 a UnicodeError to be raised when getvalue() is called.
50 def __init__(self
, buf
= ''):
51 # Force self.buf to be a string or unicode
52 if not isinstance(buf
, basestring
):
73 """Free the memory buffer.
77 del self
.buf
, self
.pos
81 raise ValueError, "I/O operation on closed file"
84 def seek(self
, pos
, mode
= 0):
86 raise ValueError, "I/O operation on closed file"
88 self
.buf
+= ''.join(self
.buflist
)
94 self
.pos
= max(0, pos
)
98 raise ValueError, "I/O operation on closed file"
101 def read(self
, n
= -1):
103 raise ValueError, "I/O operation on closed file"
105 self
.buf
+= ''.join(self
.buflist
)
110 newpos
= min(self
.pos
+n
, self
.len)
111 r
= self
.buf
[self
.pos
:newpos
]
115 def readline(self
, length
=None):
117 raise ValueError, "I/O operation on closed file"
119 self
.buf
+= ''.join(self
.buflist
)
121 i
= self
.buf
.find('\n', self
.pos
)
126 if length
is not None:
127 if self
.pos
+ length
< newpos
:
128 newpos
= self
.pos
+ length
129 r
= self
.buf
[self
.pos
:newpos
]
133 def readlines(self
, sizehint
= 0):
136 line
= self
.readline()
140 if 0 < sizehint
<= total
:
142 line
= self
.readline()
145 def truncate(self
, size
=None):
147 raise ValueError, "I/O operation on closed file"
151 raise IOError(EINVAL
, "Negative size not allowed")
152 elif size
< self
.pos
:
154 self
.buf
= self
.getvalue()[:size
]
158 raise ValueError, "I/O operation on closed file"
160 # Force s to be a string or unicode
161 if not isinstance(s
, basestring
):
163 if self
.pos
== self
.len:
164 self
.buflist
.append(s
)
165 self
.len = self
.pos
= self
.pos
+ len(s
)
167 if self
.pos
> self
.len:
168 self
.buflist
.append('\0'*(self
.pos
- self
.len))
170 newpos
= self
.pos
+ len(s
)
171 if self
.pos
< self
.len:
173 self
.buf
+= ''.join(self
.buflist
)
175 self
.buflist
= [self
.buf
[:self
.pos
], s
, self
.buf
[newpos
:]]
177 if newpos
> self
.len:
180 self
.buflist
.append(s
)
184 def writelines(self
, list):
185 self
.write(''.join(list))
189 raise ValueError, "I/O operation on closed file"
193 Retrieve the entire contents of the "file" at any time before
194 the StringIO object's close() method is called.
196 The StringIO object can accept either Unicode or 8-bit strings,
197 but mixing the two may take some care. If both are used, 8-bit
198 strings that cannot be interpreted as 7-bit ASCII (that use the
199 8th bit) will cause a UnicodeError to be raised when getvalue()
203 self
.buf
+= ''.join(self
.buflist
)
208 # A little test suite
216 lines
= open(file, 'r').readlines()
217 text
= open(file, 'r').read()
219 for line
in lines
[:-2]:
221 f
.writelines(lines
[-2:])
222 if f
.getvalue() != text
:
223 raise RuntimeError, 'write failed'
225 print 'File length =', length
226 f
.seek(len(lines
[0]))
229 print 'First line =', `f
.readline()`
230 print 'Position =', f
.tell()
232 print 'Second line =', `line`
233 f
.seek(-len(line
), 1)
234 line2
= f
.read(len(line
))
236 raise RuntimeError, 'bad result after seek back'
237 f
.seek(len(line2
), 1)
240 f
.seek(f
.tell() - len(line
))
243 raise RuntimeError, 'bad result after seek back from EOF'
244 print 'Read', len(list), 'more lines'
245 print 'File length =', f
.tell()
246 if f
.tell() != length
:
247 raise RuntimeError, 'bad length'
250 if __name__
== '__main__':