1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 BufferedFile.
21 """
22
23 from cStringIO import StringIO
24
25
27 """
28 Reusable base class to implement python-style file buffering around a
29 simpler stream.
30 """
31
32 _DEFAULT_BUFSIZE = 8192
33
34 SEEK_SET = 0
35 SEEK_CUR = 1
36 SEEK_END = 2
37
38 FLAG_READ = 0x1
39 FLAG_WRITE = 0x2
40 FLAG_APPEND = 0x4
41 FLAG_BINARY = 0x10
42 FLAG_BUFFERED = 0x20
43 FLAG_LINE_BUFFERED = 0x40
44 FLAG_UNIVERSAL_NEWLINE = 0x80
45
47 self.newlines = None
48 self._flags = 0
49 self._bufsize = self._DEFAULT_BUFSIZE
50 self._wbuffer = StringIO()
51 self._rbuffer = ''
52 self._at_trailing_cr = False
53 self._closed = False
54
55
56
57 self._pos = self._realpos = 0
58
59 self._size = 0
60
63
65 """
66 Returns an iterator that can be used to iterate over the lines in this
67 file. This iterator happens to return the file itself, since a file is
68 its own iterator.
69
70 @raise ValueError: if the file is closed.
71
72 @return: an interator.
73 @rtype: iterator
74 """
75 if self._closed:
76 raise ValueError('I/O operation on closed file')
77 return self
78
80 """
81 Close the file. Future read and write operations will fail.
82 """
83 self.flush()
84 self._closed = True
85
87 """
88 Write out any data in the write buffer. This may do nothing if write
89 buffering is not turned on.
90 """
91 self._write_all(self._wbuffer.getvalue())
92 self._wbuffer = StringIO()
93 return
94
96 """
97 Returns the next line from the input, or raises L{StopIteration} when
98 EOF is hit. Unlike python file objects, it's okay to mix calls to
99 C{next} and L{readline}.
100
101 @raise StopIteration: when the end of the file is reached.
102
103 @return: a line read from the file.
104 @rtype: str
105 """
106 line = self.readline()
107 if not line:
108 raise StopIteration
109 return line
110
111 - def read(self, size=None):
112 """
113 Read at most C{size} bytes from the file (less if we hit the end of the
114 file first). If the C{size} argument is negative or omitted, read all
115 the remaining data in the file.
116
117 @param size: maximum number of bytes to read
118 @type size: int
119 @return: data read from the file, or an empty string if EOF was
120 encountered immediately
121 @rtype: str
122 """
123 if self._closed:
124 raise IOError('File is closed')
125 if not (self._flags & self.FLAG_READ):
126 raise IOError('File is not open for reading')
127 if (size is None) or (size < 0):
128
129 result = self._rbuffer
130 self._rbuffer = ''
131 self._pos += len(result)
132 while True:
133 try:
134 new_data = self._read(self._DEFAULT_BUFSIZE)
135 except EOFError:
136 new_data = None
137 if (new_data is None) or (len(new_data) == 0):
138 break
139 result += new_data
140 self._realpos += len(new_data)
141 self._pos += len(new_data)
142 return result
143 if size <= len(self._rbuffer):
144 result = self._rbuffer[:size]
145 self._rbuffer = self._rbuffer[size:]
146 self._pos += len(result)
147 return result
148 while len(self._rbuffer) < size:
149 read_size = size - len(self._rbuffer)
150 if self._flags & self.FLAG_BUFFERED:
151 read_size = max(self._bufsize, read_size)
152 try:
153 new_data = self._read(read_size)
154 except EOFError:
155 new_data = None
156 if (new_data is None) or (len(new_data) == 0):
157 break
158 self._rbuffer += new_data
159 self._realpos += len(new_data)
160 result = self._rbuffer[:size]
161 self._rbuffer = self._rbuffer[size:]
162 self._pos += len(result)
163 return result
164
166 """
167 Read one entire line from the file. A trailing newline character is
168 kept in the string (but may be absent when a file ends with an
169 incomplete line). If the size argument is present and non-negative, it
170 is a maximum byte count (including the trailing newline) and an
171 incomplete line may be returned. An empty string is returned only when
172 EOF is encountered immediately.
173
174 @note: Unlike stdio's C{fgets()}, the returned string contains null
175 characters (C{'\\0'}) if they occurred in the input.
176
177 @param size: maximum length of returned string.
178 @type size: int
179 @return: next line of the file, or an empty string if the end of the
180 file has been reached.
181 @rtype: str
182 """
183
184 if self._closed:
185 raise IOError('File is closed')
186 if not (self._flags & self.FLAG_READ):
187 raise IOError('File not open for reading')
188 line = self._rbuffer
189 while True:
190 if self._at_trailing_cr and (self._flags & self.FLAG_UNIVERSAL_NEWLINE) and (len(line) > 0):
191
192
193 if line[0] == '\n':
194 line = line[1:]
195 self._record_newline('\r\n')
196 else:
197 self._record_newline('\r')
198 self._at_trailing_cr = False
199
200
201 if (size is not None) and (size >= 0):
202 if len(line) >= size:
203
204 self._rbuffer = line[size:]
205 line = line[:size]
206 self._pos += len(line)
207 return line
208 n = size - len(line)
209 else:
210 n = self._bufsize
211 if ('\n' in line) or ((self._flags & self.FLAG_UNIVERSAL_NEWLINE) and ('\r' in line)):
212 break
213 try:
214 new_data = self._read(n)
215 except EOFError:
216 new_data = None
217 if (new_data is None) or (len(new_data) == 0):
218 self._rbuffer = ''
219 self._pos += len(line)
220 return line
221 line += new_data
222 self._realpos += len(new_data)
223
224 pos = line.find('\n')
225 if self._flags & self.FLAG_UNIVERSAL_NEWLINE:
226 rpos = line.find('\r')
227 if (rpos >= 0) and ((rpos < pos) or (pos < 0)):
228 pos = rpos
229 xpos = pos + 1
230 if (line[pos] == '\r') and (xpos < len(line)) and (line[xpos] == '\n'):
231 xpos += 1
232 self._rbuffer = line[xpos:]
233 lf = line[pos:xpos]
234 line = line[:pos] + '\n'
235 if (len(self._rbuffer) == 0) and (lf == '\r'):
236
237
238 self._at_trailing_cr = True
239 else:
240 self._record_newline(lf)
241 self._pos += len(line)
242 return line
243
245 """
246 Read all remaining lines using L{readline} and return them as a list.
247 If the optional C{sizehint} argument is present, instead of reading up
248 to EOF, whole lines totalling approximately sizehint bytes (possibly
249 after rounding up to an internal buffer size) are read.
250
251 @param sizehint: desired maximum number of bytes to read.
252 @type sizehint: int
253 @return: list of lines read from the file.
254 @rtype: list
255 """
256 lines = []
257 bytes = 0
258 while True:
259 line = self.readline()
260 if len(line) == 0:
261 break
262 lines.append(line)
263 bytes += len(line)
264 if (sizehint is not None) and (bytes >= sizehint):
265 break
266 return lines
267
268 - def seek(self, offset, whence=0):
269 """
270 Set the file's current position, like stdio's C{fseek}. Not all file
271 objects support seeking.
272
273 @note: If a file is opened in append mode (C{'a'} or C{'a+'}), any seek
274 operations will be undone at the next write (as the file position
275 will move back to the end of the file).
276
277 @param offset: position to move to within the file, relative to
278 C{whence}.
279 @type offset: int
280 @param whence: type of movement: 0 = absolute; 1 = relative to the
281 current position; 2 = relative to the end of the file.
282 @type whence: int
283
284 @raise IOError: if the file doesn't support random access.
285 """
286 raise IOError('File does not support seeking.')
287
289 """
290 Return the file's current position. This may not be accurate or
291 useful if the underlying file doesn't support random access, or was
292 opened in append mode.
293
294 @return: file position (in bytes).
295 @rtype: int
296 """
297 return self._pos
298
300 """
301 Write data to the file. If write buffering is on (C{bufsize} was
302 specified and non-zero), some or all of the data may not actually be
303 written yet. (Use L{flush} or L{close} to force buffered data to be
304 written out.)
305
306 @param data: data to write.
307 @type data: str
308 """
309 if self._closed:
310 raise IOError('File is closed')
311 if not (self._flags & self.FLAG_WRITE):
312 raise IOError('File not open for writing')
313 if not (self._flags & self.FLAG_BUFFERED):
314 self._write_all(data)
315 return
316 self._wbuffer.write(data)
317 if self._flags & self.FLAG_LINE_BUFFERED:
318
319 last_newline_pos = data.rfind('\n')
320 if last_newline_pos >= 0:
321 wbuf = self._wbuffer.getvalue()
322 last_newline_pos += len(wbuf) - len(data)
323 self._write_all(wbuf[:last_newline_pos + 1])
324 self._wbuffer = StringIO()
325 self._wbuffer.write(wbuf[last_newline_pos + 1:])
326 return
327
328
329 if self._wbuffer.tell() >= self._bufsize:
330 self.flush()
331 return
332
334 """
335 Write a sequence of strings to the file. The sequence can be any
336 iterable object producing strings, typically a list of strings. (The
337 name is intended to match L{readlines}; C{writelines} does not add line
338 separators.)
339
340 @param sequence: an iterable sequence of strings.
341 @type sequence: sequence
342 """
343 for line in sequence:
344 self.write(line)
345 return
346
348 """
349 Identical to C{iter(f)}. This is a deprecated file interface that
350 predates python iterator support.
351
352 @return: an iterator.
353 @rtype: iterator
354 """
355 return self
356
357
358
359
360
362 """
363 I{(subclass override)}
364 Read data from the stream. Return C{None} or raise C{EOFError} to
365 indicate EOF.
366 """
367 raise EOFError()
368
370 """
371 I{(subclass override)}
372 Write data into the stream.
373 """
374 raise IOError('write not implemented')
375
377 """
378 I{(subclass override)}
379 Return the size of the file. This is called from within L{_set_mode}
380 if the file is opened in append mode, so the file position can be
381 tracked and L{seek} and L{tell} will work correctly. If the file is
382 a stream that can't be randomly accessed, you don't need to override
383 this method,
384 """
385 return 0
386
387
388
389
390
392 """
393 Subclasses call this method to initialize the BufferedFile.
394 """
395
396 self._bufsize = self._DEFAULT_BUFSIZE
397 if bufsize < 0:
398
399
400 bufsize = 0
401 if bufsize == 1:
402
403
404
405 self._flags |= self.FLAG_BUFFERED | self.FLAG_LINE_BUFFERED
406 elif bufsize > 1:
407 self._bufsize = bufsize
408 self._flags |= self.FLAG_BUFFERED
409 self._flags &= ~self.FLAG_LINE_BUFFERED
410 elif bufsize == 0:
411
412 self._flags &= ~(self.FLAG_BUFFERED | self.FLAG_LINE_BUFFERED)
413
414 if ('r' in mode) or ('+' in mode):
415 self._flags |= self.FLAG_READ
416 if ('w' in mode) or ('+' in mode):
417 self._flags |= self.FLAG_WRITE
418 if ('a' in mode):
419 self._flags |= self.FLAG_WRITE | self.FLAG_APPEND
420 self._size = self._get_size()
421 self._pos = self._realpos = self._size
422 if ('b' in mode):
423 self._flags |= self.FLAG_BINARY
424 if ('U' in mode):
425 self._flags |= self.FLAG_UNIVERSAL_NEWLINE
426
427
428
429 self.newlines = None
430
432
433
434 while len(data) > 0:
435 count = self._write(data)
436 data = data[count:]
437 if self._flags & self.FLAG_APPEND:
438 self._size += count
439 self._pos = self._realpos = self._size
440 else:
441 self._pos += count
442 self._realpos += count
443 return None
444
446
447
448
449 if not (self._flags & self.FLAG_UNIVERSAL_NEWLINE):
450 return
451 if self.newlines is None:
452 self.newlines = newline
453 elif (type(self.newlines) is str) and (self.newlines != newline):
454 self.newlines = (self.newlines, newline)
455 elif newline not in self.newlines:
456 self.newlines += (newline,)
457