# filelike/wrappers/unix.py # # Copyright (C) 2006-2008, Ryan Kelly # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # """ filelike.wrappers.unix: wrapper classes emulating unix commands This module provides filelike wrapper classes inspired by standard unix command-line programs. Currently these include: * Head: read/write only a the first N bytes or lines in a file """ import filelike from filelike.wrappers import FileWrapper class Head(FileWrapper): """Wrapper acting like unix "head" command. This wrapper limits the amount of data returned from or written to the underlying file based on the number of bytes and/or lines. This class currently does not support seeking or simultaneous read/write. NOTE: no guarantees are made about the amount of data read *from* the underlying file, only about the amount of data returned to the calling function. """ def __init__(self,fileobj,mode=None,bytes=None,lines=None): """Head wrapper constructor. The arguments 'bytes' and 'lines' specify the maximum number of bytes and lines to be read or written. Reading/writing will terminate when one of the given values has been exceeded. Any extraneous data is simply discarded. """ super(Head,self).__init__(fileobj,mode) self._maxBytes = bytes self._maxLines = lines self._bytesR = 0 self._linesR = 0 self._bytesW = 0 self._linesW = 0 self._finishedR = False self._finishedW = False def _read(self,sizehint=-1): if self._finishedR: return None if sizehint <= 0 or sizehint > self._bufsize: sizehint = self._bufsize data = self._fileobj.read(sizehint) if data == "": self._finishedR = True return data nBytes = len(data) newBytes = self._bytesR + nBytes if self._maxBytes is not None and newBytes >= self._maxBytes: data = data[:self._maxBytes - self._bytesR] self._finishedR = True nLines = data.count("\n") newLines = self._linesR + nLines if self._maxLines is not None and newLines >= self._maxLines: limit = self._maxLines - self._linesR lines = data.split("\n") if len(lines) > limit: data = "\n".join(lines[:limit]) + "\n" else: data = "\n".join(lines[:limit]) self._finishedR = True self._bytesR = newBytes self._linesR = newLines return data def _write(self,data,flushing=True): if self._finishedW: return None nBytes = len(data) nLines = data.count("\n") newBytes = self._bytesW + nBytes newLines = self._linesW + nLines if self._maxBytes is not None and newBytes >= self._maxBytes: data = data[:self._maxBytes - self._bytesW] self._finishedW = True elif self._maxLines is not None and newLines >= self._maxLines: limit = self._maxLines - self._linesW lines = data.split("\n") if len(lines) > limit: data = "\n".join(lines[:limit]) + "\n" else: data = "\n".join(lines[:limit]) self._finishedW = True self._bytesW = newBytes self._linesW = newLines self._fileobj.write(data) return None