Index: Lib/io.py =================================================================== --- Lib/io.py (Revision 58695) +++ Lib/io.py (Arbeitskopie) @@ -190,6 +190,42 @@ return open(*args, **kwargs) +class SizeInfo: + """Wrapper for size information + """ + size_names = ('B', 'KiB', 'MiB', 'GiB') + + def __init__(self, size:int): + if not isinstance(size, int) and not size >=0: + raise ValueError("Invalid size %r" % size) + self._size = size + + def __int__(self) -> int: + """int(sizeinfo) -> int + """ + return self._size + + def sizeinfo(self) -> tuple: + """sizeinfo() -> (rounded size:float, size name:int) + """ + if self._size == 0: + return 0, 0 + if self._size < 1024: + return self._size, 0 + if self._size < 1048576: + return round(self._size / 1024, 3), 1 + if self._size < 1073741824: + return round(self._size / 1048576, 3), 2 + return round(self._size / 1073741824, 3), 3 + + def __str__(self) -> str: + size, name = self.sizeinfo() + return "%1.1f %s" % (size, self.size_names[name]) + + def __repr__(self) -> str: + return "<%s %s>" % (self.__class__.__name__, self) + + class UnsupportedOperation(ValueError, IOError): pass @@ -339,6 +375,27 @@ raise ValueError("I/O operation on closed file." if msg is None else msg) + def getsize(self) -> SizeInfo: + """getsize() -> SizeInfo object + """ + size = None + self.flush() + + try: + size = os.fstat(self.fileno()).st_size + except (IOError, OSError): + pass + + if size is None: + oldpos = self.tell() + try: + self.seek(0, 2) + size = self.tell() + finally: + self.seek(oldpos) + + return SizeInfo(size) + ### Context manager ### def __enter__(self) -> "IOBase": # That's a forward reference @@ -621,6 +678,10 @@ ### Inquiries ### + def getsize(self): + self.flush() + return self.raw.getsize() + def seekable(self): return self.raw.seekable()