Files
Android-pyApi/android_pyapi/java/io.py
T
shuiyu1123 39b1da37c9 feat: 全面完善API — 补全核心类方法、存根转真实实现、Exception体系扩展
核心类方法补全:
- Activity: +20方法 (requestWindowFeature, setTitle/getTitle, onKeyDown/onKeyUp, enterPictureInPictureMode, getReferrer, isTaskRoot, navigateUpTo等)
- Fragment: +15方法 (getChildFragmentManager, getParentFragment, requireContext/requireActivity, setMenuVisibility等)
- Intent: +20方法 (getParcelableExtra, setComponent/getComponent, getDataString, getScheme, putExtras等)
- View: +20方法 (setLabelFor, setRotationX/Y, setForeground, setBackgroundTintList等)
- KeyEvent: +7方法 (getCharacters, isSystem, isPrintingKey, isModifierKey, startTracking等)
- Paint: +12方法 (setStrokeCap/Join, getTextBounds, setBlendMode, setLetterSpacing等)
- Notification.Builder: +10方法 (setProgress, setShowWhen, setOnlyAlertOnce, setSound等)

存根转真实实现:
- TrafficStats: 读取 /proc/net/dev 返回真实网络流量
- RecyclerView.Adapter: 观察者模式触发通知
- BaseAdapter: 观察者模式触发通知
- ExifInterface: 使用PIL实现图片翻转/旋转
- Process: 使用os.kill实现进程信号
- FileUtils: 真实文件I/O
- SharedPreferences: 监听器模式
- TelephonyManager.listen: 维护监听器列表
- ScrollView.smoothScrollTo: 更新滚动位置

Exception体系扩展:
- 新增15个Exception/Error类 (ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchElementException, AssertionError, OutOfMemoryError, StackOverflowError, NoClassDefFoundError, UnsatisfiedLinkError, LinkageError, VerifyError, AbstractMethodError, IncompatibleClassChangeError, ExceptionInInitializerError)

Math/System/Thread/StringBuilder/Integer增强:
- Math: +20方法 (subtractExact, multiplyExact, toIntExact, floorDiv/floorMod, fma等)
- System: getProperties/setProperties/mapLibraryName/getLogger
- Thread: +10方法 (getUncaughtExceptionHandler, getAllStackTraces, getStackTrace, holdLock等)
- StringBuilder: +7方法 (ensureCapacity, trimToSize, setLength, subSequence等)
- Integer: +8静态方法 (compare, compareUnsigned, divideUnsigned, sum, max, min等)

修复:
- app_fragment.py: 使用java.lang.IllegalStateException替代本地定义
- content_intent.py: Intent.setData/getScheme正确从Uri提取scheme
- view_ext.py: KeyEvent继承view.KeyEvent获取所有KEYCODE常量
- __init__.py: 补全Fragment/KeyEvent/MotionEvent/TrafficStats/RecyclerView等导出

统计: 221模块, 3660类, 30826方法, 180217行
2026-06-24 23:46:36 +00:00

1977 lines
54 KiB
Python

"""
Java I/O standard library APIs implemented in Python.
java.io package - File, streams, readers, writers, and exceptions.
"""
from .._core import Stub, AndroidOnlyError
import io as _pyio
import os as _os
import sys as _sys
import errno as _errno
import stat as _stat
import threading as _threading
from datetime import datetime as _datetime
from collections import OrderedDict as _OrderedDict
from pathlib import Path as _PathLibPath
__all__ = [
"Serializable", "Externalizable", "ObjectStreamField", "ObjectStreamConstants",
"FileFilter", "FilenameFilter", "File", "FileDescriptor",
"FileInputStream", "FileOutputStream",
"BufferedInputStream", "BufferedOutputStream",
"BufferedReader", "BufferedWriter",
"InputStreamReader", "OutputStreamWriter",
"FileReader", "FileWriter", "PrintWriter",
"ByteArrayInputStream", "ByteArrayOutputStream",
"StringReader", "StringWriter",
"DataInputStream", "DataOutputStream",
"ObjectInputStream", "ObjectOutputStream",
"FilterInputStream", "FilterOutputStream",
"PipedInputStream", "PipedOutputStream",
"PushbackInputStream", "SequenceInputStream",
"RandomAccessFile",
"Closeable", "Flushable",
"IOError", "IOException", "FileNotFoundException",
"EOFException", "CharConversionException",
"ObjectStreamException", "SyncFailedException",
"UTFDataFormatException", "WriteAbortedException",
"UnsupportedEncodingException",
]
# ============================================================
# Marker / mixin interfaces
# ============================================================
class Closeable(Stub):
def close(self):
raise NotImplementedError
class Flushable(Stub):
def flush(self):
raise NotImplementedError
class Serializable(Stub):
pass
class Externalizable(Stub):
pass
class ObjectStreamConstants:
STREAM_MAGIC = 0xACED
STREAM_VERSION = 5
TC_BASE = 0x70
TC_NULL = 0x70
TC_REFERENCE = 0x71
TC_CLASS = 0x72
TC_OBJECT = 0x73
TC_STRING = 0x74
TC_ARRAY = 0x75
TC_ENUM = 0x7E
TC_CLASSDESC = 0x72
TC_PROXYCLASSDESC = 0x7D
TC_BLOCKDATA = 0x77
TC_ENDBLOCKDATA = 0x78
TC_RESET = 0x79
TC_EXCEPTION = 0x7A
TC_LONGSTRING = 0x7C
baseWireHandle = 0x7E0000
class ObjectStreamField(Stub):
def __init__(self, name, typ):
self._name = name
self._type = typ
def getName(self):
return self._name
def getType(self):
return self._type
def toString(self):
return f"{self._type} {self._name}"
# ============================================================
# FileFilter / FilenameFilter
# ============================================================
class FileFilter(Stub):
def accept(self, pathname):
raise NotImplementedError
class FilenameFilter(Stub):
def accept(self, dir, name):
raise NotImplementedError
# ============================================================
# FileDescriptor
# ============================================================
class FileDescriptor(Stub):
_valid_fd = -1
def __init__(self, fd=None):
super().__init__()
if fd is not None:
self._valid_fd = fd
def valid(self):
return self._valid_fd >= 0
def sync(self):
if self._valid_fd >= 0:
try:
_os.fsync(self._valid_fd)
except OSError:
pass
def hashCode(self):
return self._valid_fd
@staticmethod
def _from_fileno(fd):
return FileDescriptor(fd)
# ============================================================
# Exception classes
# ============================================================
class IOException(Exception):
def __init__(self, message=None, cause=None):
super().__init__(message)
self._cause = cause
def getCause(self):
return self._cause
class FileNotFoundException(IOException):
pass
class EOFException(IOException):
pass
class CharConversionException(IOException):
pass
class ObjectStreamException(IOException):
pass
class SyncFailedException(IOException):
pass
class UTFDataFormatException(IOException):
pass
class WriteAbortedException(ObjectStreamException):
def __init__(self, message=None, cause=None):
super().__init__(message)
self.detail = cause
class UnsupportedEncodingException(IOException):
pass
class IOError(Exception):
def __init__(self, message=None, cause=None):
super().__init__(message)
self._cause = cause
def getCause(self):
return self._cause
# ============================================================
# File
# ============================================================
class File(Stub):
separator = _os.sep
separatorChar = _os.sep
pathSeparator = _os.pathsep
pathSeparatorChar = _os.pathsep
def __init__(self, *args):
super().__init__()
if len(args) == 1:
path = args[0]
if isinstance(path, File):
self._path = path._path
else:
self._path = str(path)
elif len(args) == 2:
parent, child = args
if parent is None:
self._path = str(child)
else:
parent_str = parent._path if isinstance(parent, File) else str(parent)
child_str = str(child)
if child_str.startswith(self.separator):
self._path = child_str
else:
self._path = _os.path.join(parent_str, child_str)
else:
self._path = ""
self._path = self._path or ""
def _resolve(self):
return _os.path.realpath(self._path) if self._path else ""
def exists(self):
return _os.path.exists(self._path)
def isFile(self):
return _os.path.isfile(self._path)
def isDirectory(self):
return _os.path.isdir(self._path)
def getName(self):
return _os.path.basename(self._path)
def getPath(self):
return self._path
def getAbsolutePath(self):
return _os.path.abspath(self._path)
def getCanonicalPath(self):
try:
return _os.path.realpath(self._path)
except Exception:
return self.getAbsolutePath()
def getParent(self):
p = _os.path.dirname(self._path)
return p if p else None
def getParentFile(self):
p = self.getParent()
return File(p) if p else None
def length(self):
try:
return _os.path.getsize(self._path)
except OSError:
return 0
def lastModified(self):
try:
return int(_os.path.getmtime(self._path) * 1000)
except OSError:
return 0
def createNewFile(self):
try:
f = _os.open(self._path, _os.O_CREAT | _os.O_EXCL, 0o644)
_os.close(f)
return True
except OSError:
return False
def delete(self):
try:
if self.isDirectory():
_os.rmdir(self._path)
else:
_os.remove(self._path)
return True
except OSError:
return False
def mkdir(self):
try:
_os.mkdir(self._path)
return True
except OSError:
return False
def mkdirs(self):
try:
_os.makedirs(self._path, exist_ok=True)
return True
except OSError:
return False
def renameTo(self, dest):
try:
dest_path = dest._path if isinstance(dest, File) else str(dest)
_os.rename(self._path, dest_path)
return True
except OSError:
return False
def list(self):
try:
return _os.listdir(self._path)
except OSError:
return None
def listFiles(self, filter=None):
try:
names = _os.listdir(self._path)
files = [File(self._path, n) for n in names]
if filter:
return [f for f in files if filter.accept(f)]
return files
except OSError:
return None
@staticmethod
def listRoots():
if _sys.platform == "win32":
import string
return [File(d + ":\\") for d in string.ascii_uppercase if _os.path.exists(d + ":\\")]
return [File("/")]
def canRead(self):
return _os.access(self._path, _os.R_OK)
def canWrite(self):
return _os.access(self._path, _os.W_OK)
def canExecute(self):
return _os.access(self._path, _os.X_OK)
def setReadable(self, readable, ownerOnly=True):
try:
if readable:
if ownerOnly:
_os.chmod(self._path, _stat.S_IRUSR | (_stat.S_IRGRP if _os.stat(self._path).st_gid else 0))
else:
_os.chmod(self._path, _stat.S_IRUSR | _stat.S_IRGRP | _stat.S_IROTH)
else:
mode = _os.stat(self._path).st_mode
if ownerOnly:
mode &= ~_stat.S_IRUSR
else:
mode &= ~(_stat.S_IRUSR | _stat.S_IRGRP | _stat.S_IROTH)
_os.chmod(self._path, mode)
return True
except OSError:
return False
def setWritable(self, writable, ownerOnly=True):
try:
if writable:
if ownerOnly:
_os.chmod(self._path, _stat.S_IWUSR)
else:
_os.chmod(self._path, _stat.S_IWUSR | _stat.S_IWGRP | _stat.S_IWOTH)
else:
mode = _os.stat(self._path).st_mode
if ownerOnly:
mode &= ~_stat.S_IWUSR
else:
mode &= ~(_stat.S_IWUSR | _stat.S_IWGRP | _stat.S_IWOTH)
_os.chmod(self._path, mode)
return True
except OSError:
return False
def setExecutable(self, executable, ownerOnly=True):
try:
if executable:
if ownerOnly:
_os.chmod(self._path, _stat.S_IXUSR)
else:
_os.chmod(self._path, _stat.S_IXUSR | _stat.S_IXGRP | _stat.S_IXOTH)
else:
mode = _os.stat(self._path).st_mode
if ownerOnly:
mode &= ~_stat.S_IXUSR
else:
mode &= ~(_stat.S_IXUSR | _stat.S_IXGRP | _stat.S_IXOTH)
_os.chmod(self._path, mode)
return True
except OSError:
return False
def isHidden(self):
return _os.path.basename(self._path).startswith(".")
def toURL(self):
from urllib.parse import quote
return f"file:{quote(self.getAbsolutePath())}"
def toURI(self):
return self.toURL()
def getTotalSpace(self):
try:
st = _os.statvfs(self._path)
return st.f_frsize * st.f_blocks
except OSError:
return 0
def getFreeSpace(self):
try:
st = _os.statvfs(self._path)
return st.f_frsize * st.f_bfree
except OSError:
return 0
def getUsableSpace(self):
try:
st = _os.statvfs(self._path)
return st.f_frsize * st.f_bavail
except OSError:
return 0
def compareTo(self, other) -> int:
if isinstance(other, File):
if self._path < other._path:
return -1
elif self._path > other._path:
return 1
return 0
return -1
def equals(self, other):
if isinstance(other, File):
return self._path == other._path
return False
def hashCode(self):
return hash(self._path) & 0x7FFFFFFF
def toString(self):
return self._path
def toPath(self):
return _PathLibPath(self._path)
@staticmethod
def createTempFile(prefix, suffix=None, directory=None):
import tempfile
if directory:
fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix or ".tmp", dir=directory)
else:
fd, path = tempfile.mkstemp(prefix=prefix, suffix=suffix or ".tmp")
_os.close(fd)
return File(path)
def deleteOnExit(self):
import atexit
atexit.register(lambda: self.delete() if self.exists() else None)
def setLastModified(self, time):
try:
_os.utime(self._path, (time / 1000, time / 1000))
return True
except Exception:
return False
def setReadOnly(self):
try:
_os.chmod(self._path, 0o444)
return True
except Exception:
return False
def isAbsolute(self):
return _os.path.isabs(self._path)
def getAbsoluteFile(self):
return File(self.getAbsolutePath())
def getCanonicalFile(self):
return File(self.getCanonicalPath())
def __str__(self):
return self._path
def __repr__(self):
return f"File({self._path!r})"
# ============================================================
# FileInputStream
# ============================================================
class FileInputStream(Closeable):
def __init__(self, file):
super().__init__()
if isinstance(file, File):
path = file.getPath()
else:
path = str(file)
self._path = path
self._fd = None
self._channel = None
self._closed = False
try:
self._fd = _os.open(path, _os.O_RDONLY)
except OSError as e:
raise FileNotFoundException(str(e))
def read(self, b=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if b is None:
data = _os.read(self._fd, 1)
return data[0] if data else -1
if isinstance(b, (bytes, bytearray)):
if off is None:
off = 0
if length is None:
length = len(b) - off
data = _os.read(self._fd, length)
if not data:
return -1
n = len(data)
if isinstance(b, bytearray):
b[off:off+n] = data
else:
ba = bytearray(b)
ba[off:off+n] = data
b[:] = bytes(ba)
return n
return -1
def skip(self, n):
try:
pos = _os.lseek(self._fd, 0, _os.SEEK_CUR)
end = _os.lseek(self._fd, 0, _os.SEEK_END)
_os.lseek(self._fd, pos, _os.SEEK_SET)
actual = min(n, end - pos)
_os.lseek(self._fd, actual, _os.SEEK_CUR)
return actual
except OSError:
return 0
def available(self):
if self._closed:
return 0
try:
pos = _os.lseek(self._fd, 0, _os.SEEK_CUR)
end = _os.lseek(self._fd, 0, _os.SEEK_END)
_os.lseek(self._fd, pos, _os.SEEK_SET)
return end - pos
except OSError:
return 0
def close(self):
if not self._closed:
self._closed = True
if self._fd is not None:
_os.close(self._fd)
self._fd = None
def getFD(self):
if self._closed:
raise IOException("Stream closed")
return FileDescriptor(self._fd)
def getChannel(self):
if self._closed:
raise IOException("Stream closed")
if self._channel is None:
import io as _pyio_mod
self._channel = _pyio_mod.FileIO(self._fd, closefd=False)
return self._channel
def __del__(self):
self.close()
# ============================================================
# FileOutputStream
# ============================================================
class FileOutputStream(Closeable, Flushable):
def __init__(self, file, append=False):
super().__init__()
if isinstance(file, File):
path = file.getPath()
elif isinstance(file, FileDescriptor):
self._fd = file._valid_fd
self._path = None
self._closed = False
self._channel = None
return
else:
path = str(file)
self._path = path
self._closed = False
self._channel = None
try:
flags = _os.O_WRONLY | _os.O_CREAT
if append:
flags |= _os.O_APPEND
else:
flags |= _os.O_TRUNC
self._fd = _os.open(path, flags, 0o644)
except OSError as e:
raise FileNotFoundException(str(e))
def write(self, b=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if b is None:
return
if isinstance(b, int):
_os.write(self._fd, bytes([b]))
elif isinstance(b, (bytes, bytearray)):
if off is None:
data = bytes(b)
else:
data = bytes(b[off:off+length if length else (len(b)-off)])
_os.write(self._fd, data)
else:
if off is None:
data = bytes(b)
else:
data = bytes(b[off:off+length if length else (len(b)-off)])
_os.write(self._fd, data)
def close(self):
if not self._closed:
self._closed = True
if self._fd is not None:
_os.close(self._fd)
self._fd = None
def getFD(self):
if self._closed:
raise IOException("Stream closed")
return FileDescriptor(self._fd)
def getChannel(self):
if self._closed:
raise IOException("Stream closed")
if self._channel is None:
import io as _pyio_mod
self._channel = _pyio_mod.FileIO(self._fd, closefd=False, mode='ab')
return self._channel
def flush(self):
if self._fd is not None:
try:
_os.fsync(self._fd)
except OSError:
pass
def __del__(self):
self.close()
# ============================================================
# FilterInputStream / FilterOutputStream (abstract wrappers)
# ============================================================
class FilterInputStream(Closeable):
def __init__(self, inp):
super().__init__()
self._in = inp
def read(self, *args):
return self._in.read(*args)
def skip(self, n):
return self._in.skip(n)
def available(self):
return self._in.available()
def close(self):
self._in.close()
def mark(self, readlimit):
pass
def reset(self):
raise IOException("mark/reset not supported")
def markSupported(self):
return False
class FilterOutputStream(Closeable, Flushable):
def __init__(self, out):
super().__init__()
self._out = out
def write(self, *args):
self._out.write(*args)
def close(self):
self._out.close()
def flush(self):
self._out.flush()
# ============================================================
# BufferedInputStream
# ============================================================
class BufferedInputStream(FilterInputStream):
def __init__(self, inp, size=8192):
super().__init__(inp)
self._buffer = bytearray()
self._buf_size = size
self._pos = 0
self._count = 0
def read(self, b=None, off=None, length=None):
if b is None:
if self._pos >= self._count:
self._fill()
if self._pos >= self._count:
return -1
val = self._buffer[self._pos]
self._pos += 1
return val
if off is None:
off = 0
if length is None:
length = len(b)
total = 0
while total < length:
if self._pos >= self._count:
if not self._fill():
break
chunk = min(length - total, self._count - self._pos)
if isinstance(b, bytearray):
b[off+total:off+total+chunk] = self._buffer[self._pos:self._pos+chunk]
else:
ba = bytearray(b)
ba[off+total:off+total+chunk] = self._buffer[self._pos:self._pos+chunk]
b[:] = bytes(ba)
self._pos += chunk
total += chunk
return total if total > 0 else -1
def _fill(self):
data = self._in.read(bytearray(self._buf_size), 0, self._buf_size)
if data is None or data == -1:
return False
n = data if isinstance(data, int) else len(data)
self._buffer = bytearray(self._in._buffer if hasattr(self._in, '_buffer') else data) if n > 0 else bytearray()
self._pos = 0
self._count = n
return n > 0
# ============================================================
# BufferedOutputStream
# ============================================================
class BufferedOutputStream(FilterOutputStream):
def __init__(self, out, size=8192):
super().__init__(out)
self._buf = bytearray()
self._buf_size = size
def write(self, b=None, off=None, length=None):
if b is None:
return
if isinstance(b, int):
self._buf.append(b & 0xFF)
else:
if off is not None and length is not None:
data = b[off:off+length]
else:
data = b
self._buf.extend(data)
if len(self._buf) >= self._buf_size:
self.flush()
def flush(self):
if self._buf:
self._out.write(bytes(self._buf))
self._buf.clear()
self._out.flush()
# ============================================================
# InputStreamReader
# ============================================================
class InputStreamReader(Closeable):
def __init__(self, inp, charset=None):
super().__init__()
self._in = inp
self._charset = charset or "utf-8"
self._buffer = None
def read(self, cbuf=None, off=None, length=None):
if cbuf is None:
data = self._in.read()
if data is None or data == -1:
return -1
return data & 0xFF
if off is None:
off = 0
if length is None:
length = len(cbuf)
raw = self._in.read(bytearray(length), 0, length)
if raw is None or raw == -1:
return -1
n = len(raw) if isinstance(raw, (bytes, bytearray)) else raw
if isinstance(raw, int):
return raw
decoded = raw.decode(self._charset, errors='replace')
for i, ch in enumerate(decoded):
if off + i < len(cbuf):
cbuf[off + i] = ch
return len(decoded)
def getEncoding(self):
return self._charset
def close(self):
self._in.close()
# ============================================================
# OutputStreamWriter
# ============================================================
class OutputStreamWriter(Closeable, Flushable):
def __init__(self, out, charset=None):
super().__init__()
self._out = out
self._charset = charset or "utf-8"
def write(self, s, off=None, length=None):
if isinstance(s, str):
if off is not None and length is not None:
s = s[off:off+length]
self._out.write(s.encode(self._charset))
elif isinstance(s, (list, tuple)):
chars = "".join(s)
if off is not None and length is not None:
chars = chars[off:off+length]
self._out.write(chars.encode(self._charset))
def flush(self):
self._out.flush()
def close(self):
self._out.close()
def getEncoding(self):
return self._charset
# ============================================================
# FileReader
# ============================================================
class FileReader(InputStreamReader):
def __init__(self, file):
if isinstance(file, File):
path = file.getPath()
else:
path = str(file)
inp = FileInputStream(path)
super().__init__(inp, "utf-8")
self._file_path = path
# ============================================================
# FileWriter
# ============================================================
class FileWriter(OutputStreamWriter):
def __init__(self, file, append=False):
if isinstance(file, File):
path = file.getPath()
append = append
else:
path = str(file)
out = FileOutputStream(path, append)
super().__init__(out, "utf-8")
self._file_path = path
# ============================================================
# BufferedReader
# ============================================================
class BufferedReader(Closeable):
def __init__(self, reader, size=8192):
super().__init__()
self._reader = reader
self._buf_size = size
self._buffer = ""
self._pos = 0
self._closed = False
def read(self, cbuf=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if cbuf is None:
if self._pos >= len(self._buffer):
self._fill()
if self._pos >= len(self._buffer):
return -1
ch = ord(self._buffer[self._pos])
self._pos += 1
return ch
if off is None:
off = 0
if length is None:
length = len(cbuf)
total = 0
while total < length:
if self._pos >= len(self._buffer):
if not self._fill():
break
chunk = min(length - total, len(self._buffer) - self._pos)
for i in range(chunk):
cbuf[off + total + i] = self._buffer[self._pos + i]
self._pos += chunk
total += chunk
return total if total > 0 else -1
def _fill(self):
if hasattr(self._reader, '_in'):
raw = self._reader._in.read(bytearray(self._buf_size), 0, self._buf_size)
if raw is None or raw == -1:
return False
data = bytes(raw) if isinstance(raw, int) else bytes(raw)
self._buffer = data.decode(self._reader.getEncoding() if hasattr(self._reader, 'getEncoding') else "utf-8", errors='replace')
else:
raw = []
for _ in range(self._buf_size):
ch = self._reader.read()
if ch == -1:
break
raw.append(chr(ch))
self._buffer = "".join(raw)
self._pos = 0
return len(self._buffer) > 0
def readLine(self):
if self._closed:
raise IOException("Stream closed")
result = []
while True:
if self._pos >= len(self._buffer):
if not self._fill():
break
while self._pos < len(self._buffer):
ch = self._buffer[self._pos]
self._pos += 1
if ch == "\n":
return "".join(result)
if ch == "\r":
if self._pos < len(self._buffer) and self._buffer[self._pos] == "\n":
self._pos += 1
return "".join(result)
result.append(ch)
return "".join(result) if result else None
def ready(self):
return self._pos < len(self._buffer)
def mark(self, readAheadLimit):
self._mark_pos = self._pos
self._mark_buffer = self._buffer
def reset(self):
if hasattr(self, '_mark_pos'):
self._pos = self._mark_pos
self._buffer = self._mark_buffer
else:
raise IOException("Mark not set")
def markSupported(self):
return True
def skip(self, n):
skipped = 0
while skipped < n:
if self._pos >= len(self._buffer):
if not self._fill():
break
chunk = min(n - skipped, len(self._buffer) - self._pos)
self._pos += chunk
skipped += chunk
return skipped
def close(self):
self._closed = True
self._reader.close()
def lines(self):
line = self.readLine()
while line is not None:
yield line
line = self.readLine()
# ============================================================
# BufferedWriter
# ============================================================
class BufferedWriter(Closeable, Flushable):
def __init__(self, writer, size=8192):
super().__init__()
self._writer = writer
self._buf_size = size
self._buffer = []
def write(self, s, off=None, length=None):
if isinstance(s, str):
if off is not None and length is not None:
s = s[off:off+length]
self._buffer.append(s)
elif isinstance(s, (list, tuple)):
chars = "".join(s)
if off is not None and length is not None:
chars = chars[off:off+length]
self._buffer.append(chars)
elif isinstance(s, int):
self._buffer.append(chr(s))
if sum(len(x) for x in self._buffer) >= self._buf_size:
self.flush()
def newLine(self):
self._buffer.append("\n")
def flush(self):
if self._buffer:
data = "".join(self._buffer)
self._writer.write(data)
self._buffer.clear()
self._writer.flush()
def close(self):
self.flush()
self._writer.close()
# ============================================================
# PrintWriter
# ============================================================
class PrintWriter(Closeable, Flushable):
def __init__(self, out, autoFlush=False):
super().__init__()
if isinstance(out, _pyio.TextIOBase):
self._out = out
else:
self._out = out
self._auto_flush = autoFlush
self._error = False
def _write_str(self, s):
s = str(s)
if hasattr(self._out, 'write'):
self._out.write(s)
else:
self._out.write(s.encode('utf-8'))
def print_bool(self, b):
self._write_str(str(b))
if self._auto_flush:
self.flush()
def print_char(self, c):
self._write_str(str(c))
if self._auto_flush:
self.flush()
def print_char_array(self, c):
self._write_str("".join(c))
if self._auto_flush:
self.flush()
def print_double(self, d):
self._write_str(str(d))
if self._auto_flush:
self.flush()
def print_float(self, f):
self._write_str(str(f))
if self._auto_flush:
self.flush()
def print_int(self, i):
self._write_str(str(i))
if self._auto_flush:
self.flush()
def print_long(self, l):
self._write_str(str(l))
if self._auto_flush:
self.flush()
def print_obj(self, obj):
self._write_str(str(obj))
if self._auto_flush:
self.flush()
def print_str(self, s):
self._write_str(str(s) if s is not None else "null")
if self._auto_flush:
self.flush()
print = print_str
print_boolean = print_bool
def println(self, s=None):
if s is None:
self._write_str("\n")
else:
self._write_str(str(s) + "\n")
if self._auto_flush:
self.flush()
def println_bool(self, b):
self._write_str(str(b) + "\n")
if self._auto_flush:
self.flush()
def println_char(self, c):
self._write_str(str(c) + "\n")
if self._auto_flush:
self.flush()
def println_char_array(self, c):
self._write_str("".join(c) + "\n")
if self._auto_flush:
self.flush()
def println_double(self, d):
self._write_str(str(d) + "\n")
if self._auto_flush:
self.flush()
def println_float(self, f):
self._write_str(str(f) + "\n")
if self._auto_flush:
self.flush()
def println_int(self, i):
self._write_str(str(i) + "\n")
if self._auto_flush:
self.flush()
def println_long(self, l):
self._write_str(str(l) + "\n")
if self._auto_flush:
self.flush()
def println_obj(self, obj):
self._write_str(str(obj) + "\n")
if self._auto_flush:
self.flush()
def write(self, s, off=None, length=None):
if isinstance(s, str):
if off is not None and length is not None:
s = s[off:off+length]
self._write_str(s)
else:
self._write_str(str(s))
def format(self, fmt, *args):
s = str(fmt) % args if args else str(fmt)
self._write_str(s)
return self
def printf(self, fmt, *args):
return self.format(fmt, *args)
def flush(self):
if hasattr(self._out, 'flush'):
self._out.flush()
def close(self):
self.flush()
if hasattr(self._out, 'close'):
self._out.close()
def checkError(self):
return self._error
def setError(self):
self._error = True
# ============================================================
# ByteArrayInputStream
# ============================================================
class ByteArrayInputStream(Closeable):
def __init__(self, buf):
super().__init__()
self._buf = bytes(buf)
self._pos = 0
self._count = len(self._buf)
self._mark = 0
self._closed = False
def read(self, b=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if b is None:
if self._pos >= self._count:
return -1
val = self._buf[self._pos] & 0xFF
self._pos += 1
return val
if off is None:
off = 0
if length is None:
length = len(b)
avail = self._count - self._pos
if avail <= 0:
return -1
n = min(length, avail)
if isinstance(b, bytearray):
b[off:off+n] = self._buf[self._pos:self._pos+n]
else:
ba = bytearray(b)
ba[off:off+n] = self._buf[self._pos:self._pos+n]
b[:] = bytes(ba)
self._pos += n
return n
def skip(self, n):
if self._closed:
return 0
avail = self._count - self._pos
actual = min(n, avail)
self._pos += actual
return actual
def available(self):
if self._closed:
return 0
return self._count - self._pos
def close(self):
self._closed = True
def mark(self, readAheadLimit):
self._mark = self._pos
def reset(self):
self._pos = self._mark
# ============================================================
# ByteArrayOutputStream
# ============================================================
class ByteArrayOutputStream(Closeable, Flushable):
def __init__(self, size=32):
super().__init__()
self._buf = bytearray()
self._closed = False
def write(self, b=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if b is None:
return
if isinstance(b, int):
self._buf.append(b & 0xFF)
elif isinstance(b, (bytes, bytearray)):
if off is not None and length is not None:
self._buf.extend(b[off:off+length])
else:
self._buf.extend(b)
def toByteArray(self):
return bytes(self._buf)
def size(self):
return len(self._buf)
def toString(self, charset=None):
if charset:
return bytes(self._buf).decode(charset, errors='replace')
return bytes(self._buf).decode('utf-8', errors='replace')
def reset(self):
self._buf.clear()
def close(self):
self._closed = True
def flush(self):
pass
# ============================================================
# StringReader
# ============================================================
class StringReader(Closeable):
def __init__(self, s):
super().__init__()
self._str = s
self._pos = 0
self._length = len(s)
self._mark = 0
self._closed = False
def read(self, cbuf=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if cbuf is None:
if self._pos >= self._length:
return -1
val = ord(self._str[self._pos])
self._pos += 1
return val
if off is None:
off = 0
if length is None:
length = len(cbuf)
avail = self._length - self._pos
if avail <= 0:
return -1
n = min(length, avail)
for i in range(n):
cbuf[off + i] = self._str[self._pos + i]
self._pos += n
return n
def skip(self, n):
avail = self._length - self._pos
actual = min(n, avail)
self._pos += actual
return max(actual, 0)
def ready(self):
return self._pos < self._length
def mark(self, readAheadLimit):
self._mark = self._pos
def reset(self):
self._pos = self._mark
def markSupported(self):
return True
def close(self):
self._closed = True
# ============================================================
# StringWriter
# ============================================================
class StringWriter(Closeable, Flushable):
def __init__(self):
super().__init__()
self._buffer = []
self._closed = False
def write(self, s, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if isinstance(s, str):
if off is not None and length is not None:
s = s[off:off+length]
self._buffer.append(s)
elif isinstance(s, int):
self._buffer.append(chr(s))
elif isinstance(s, (list, tuple)):
chars = "".join(s)
if off is not None and length is not None:
chars = chars[off:off+length]
self._buffer.append(chars)
def flush(self):
pass
def close(self):
self._closed = True
def toString(self):
return "".join(self._buffer)
def getBuffer(self):
return "".join(self._buffer)
# ============================================================
# DataInputStream
# ============================================================
class DataInputStream(Closeable):
def __init__(self, inp):
super().__init__()
self._in = inp
def read(self, b=None):
if b is None:
return self._in.read()
return self._in.read(b)
def readBoolean(self):
v = self._in.read()
if v == -1:
raise EOFException()
return bool(v)
def readByte(self):
v = self._in.read()
if v == -1:
raise EOFException()
return (v & 0xFF) if v <= 127 else (v - 256)
def readChar(self):
hi = self._in.read()
lo = self._in.read()
if hi == -1 or lo == -1:
raise EOFException()
return chr((hi << 8) | lo)
def readDouble(self):
return _struct.unpack(">d", self._read_bytes(8))[0]
def readFloat(self):
return _struct.unpack(">f", self._read_bytes(4))[0]
def readFully(self, b, off=0, length=None):
if length is None:
length = len(b)
total = 0
while total < length:
n = self._in.read(b, off + total, length - total)
if n == -1:
raise EOFException()
total += n
def readInt(self):
return _struct.unpack(">i", self._read_bytes(4))[0]
def readLong(self):
return _struct.unpack(">q", self._read_bytes(8))[0]
def readShort(self):
v = _struct.unpack(">h", self._read_bytes(2))[0]
return v
def readUTF(self):
length = self.readUnsignedShort()
data = self._read_bytes(length)
return data.decode("utf-8")
def readUnsignedByte(self):
v = self._in.read()
if v == -1:
raise EOFException()
return v & 0xFF
def readUnsignedShort(self):
hi = self._in.read()
lo = self._in.read()
if hi == -1 or lo == -1:
raise EOFException()
return ((hi & 0xFF) << 8) | (lo & 0xFF)
def skipBytes(self, n):
return self._in.skip(n)
def _read_bytes(self, n):
buf = bytearray(n)
total = 0
while total < n:
r = self._in.read(buf, total, n - total)
if r == -1:
raise EOFException()
total += r
return bytes(buf)
def close(self):
self._in.close()
# ============================================================
# DataOutputStream
# ============================================================
import struct as _struct
class DataOutputStream(Closeable, Flushable):
def __init__(self, out):
super().__init__()
self._out = out
self._written = 0
def write(self, b=None, off=None, length=None):
if b is not None:
self._out.write(b, off, length)
self._written += length if length else (len(b) if isinstance(b, (bytes, bytearray)) else 1)
def writeBoolean(self, v):
self._out.write(int(v))
def writeByte(self, v):
self._out.write(v & 0xFF)
def writeBytes(self, s):
for ch in str(s):
self._out.write(ord(ch) & 0xFF)
def writeChar(self, v):
self._out.write((v >> 8) & 0xFF)
self._out.write(v & 0xFF)
def writeChars(self, s):
for ch in str(s):
self.writeChar(ord(ch))
def writeDouble(self, v):
self._write_struct(">d", v)
def writeFloat(self, v):
self._write_struct(">f", v)
def writeInt(self, v):
self._write_struct(">i", v)
def writeLong(self, v):
self._write_struct(">q", v)
def writeShort(self, v):
self._write_struct(">h", v)
def writeUTF(self, s):
encoded = str(s).encode("utf-8")
self.writeShort(len(encoded))
for b in encoded:
self._out.write(b)
def size(self):
return self._written
def _write_struct(self, fmt, v):
data = _struct.pack(fmt, v)
for b in data:
self._out.write(b)
def flush(self):
self._out.flush()
def close(self):
self._out.close()
# ============================================================
# ObjectInputStream / ObjectOutputStream (stub)
# ============================================================
class ObjectInputStream(Closeable):
def __init__(self, inp):
super().__init__()
self._in = inp
def readObject(self):
raise AndroidOnlyError("ObjectInputStream.readObject()")
def readInt(self):
return DataInputStream(self._in).readInt()
def close(self):
self._in.close()
class ObjectOutputStream(Closeable, Flushable):
def __init__(self, out):
super().__init__()
self._out = out
def writeObject(self, obj):
raise AndroidOnlyError("ObjectOutputStream.writeObject()")
def writeInt(self, v):
DataOutputStream(self._out).writeInt(v)
def flush(self):
self._out.flush()
def close(self):
self._out.close()
# ============================================================
# PipedInputStream / PipedOutputStream
# ============================================================
class PipedInputStream(Closeable):
def __init__(self, src=None, pipe_size=1024):
super().__init__()
self._buffer = bytearray()
self._pipe_size = pipe_size
self._closed = False
self._lock = _threading.RLock()
self._data_available = _threading.Condition(self._lock)
if src:
src.connect(self)
def connect(self, src):
src._sink = self
def receive(self, b):
with self._lock:
self._buffer.append(b & 0xFF)
self._data_available.notify()
def read(self, b=None, off=None, length=None):
with self._lock:
while len(self._buffer) == 0 and not self._closed:
self._data_available.wait(timeout=1)
if self._closed and len(self._buffer) == 0:
return -1
if b is None:
if len(self._buffer) == 0:
return -1
return self._buffer.pop(0)
if off is None:
off = 0
if length is None:
length = len(b)
n = min(length, len(self._buffer))
for i in range(n):
if isinstance(b, bytearray):
b[off + i] = self._buffer.pop(0)
else:
b[off + i] = self._buffer.pop(0)
return n
def close(self):
with self._lock:
self._closed = True
self._data_available.notify_all()
class PipedOutputStream(Closeable):
def __init__(self, sink=None):
super().__init__()
self._sink = sink
def connect(self, sink):
self._sink = sink
def write(self, b, off=None, length=None):
if self._sink is None:
raise IOException("Pipe not connected")
if isinstance(b, int):
self._sink.receive(b)
else:
if off is not None and length is not None:
for i in range(off, off + length):
self._sink.receive(b[i])
else:
for byte in b:
self._sink.receive(byte)
def flush(self):
pass
def close(self):
if self._sink:
self._sink.close()
# ============================================================
# PushbackInputStream
# ============================================================
class PushbackInputStream(FilterInputStream):
def __init__(self, inp, size=1):
super().__init__(inp)
self._pushback_buf = bytearray()
self._max_size = size
def read(self, b=None, off=None, length=None):
if b is None:
if self._pushback_buf:
return self._pushback_buf.pop(0)
return self._in.read()
if off is None:
off = 0
if length is None:
length = len(b)
total = 0
while self._pushback_buf and total < length:
if isinstance(b, bytearray):
b[off + total] = self._pushback_buf.pop(0)
else:
ba = bytearray(b)
ba[off + total] = self._pushback_buf.pop(0)
b[:] = bytes(ba)
total += 1
if total < length:
n = self._in.read(b, off + total, length - total)
if n > 0:
total += n
return total if total > 0 else -1
def unread(self, b):
if isinstance(b, int):
if len(self._pushback_buf) >= self._max_size:
raise IOException("Pushback buffer overflow")
self._pushback_buf.append(b & 0xFF)
else:
for byte_val in b:
self.unread(byte_val)
def close(self):
self._pushback_buf.clear()
self._in.close()
# ============================================================
# SequenceInputStream
# ============================================================
class SequenceInputStream(Closeable):
def __init__(self, streams):
super().__init__()
if hasattr(streams, 'hasMoreElements'):
self._streams = []
while streams.hasMoreElements():
self._streams.append(streams.nextElement())
else:
self._streams = list(streams)
self._current_idx = 0
def _current(self):
if self._current_idx < len(self._streams):
return self._streams[self._current_idx]
return None
def read(self, b=None, off=None, length=None):
while self._current():
inp = self._current()
if b is None:
result = inp.read()
else:
result = inp.read(b, off, length)
if result != -1:
return result
self._current_idx += 1
return -1
def close(self):
for s in self._streams:
s.close()
# ============================================================
# RandomAccessFile
# ============================================================
class RandomAccessFile(Closeable, Flushable):
def __init__(self, file, mode="r"):
super().__init__()
if isinstance(file, File):
path = file.getPath()
else:
path = str(file)
self._path = path
self._mode = mode
self._closed = False
py_modes = {"r": "rb", "rw": "r+b", "rws": "r+b", "rwd": "r+b"}
py_mode = py_modes.get(mode, "r+b")
try:
if "w" in mode and mode != "r":
self._file = open(path, py_mode)
else:
self._file = open(path, py_mode)
except FileNotFoundError as e:
if "w" in mode:
self._file = open(path, "w+b")
else:
raise FileNotFoundException(str(e))
def seek(self, pos):
self._file.seek(pos)
def getFilePointer(self):
return self._file.tell()
def length(self):
pos = self._file.tell()
self._file.seek(0, 2)
end = self._file.tell()
self._file.seek(pos)
return end
def read(self, b=None, off=None, length=None):
if b is None:
data = self._file.read(1)
return data[0] if data else -1
if off is None:
off = 0
if length is None:
length = len(b)
data = self._file.read(length)
if not data:
return -1
n = len(data)
if isinstance(b, bytearray):
b[off:off+n] = data
else:
ba = bytearray(b)
ba[off:off+n] = data
b[:] = bytes(ba)
return n
def readBoolean(self):
v = self.read()
if v == -1:
raise EOFException()
return bool(v)
def readByte(self):
v = self.read()
if v == -1:
raise EOFException()
return (v & 0xFF) if v <= 127 else (v - 256)
def readChar(self):
hi = self.read()
lo = self.read()
if hi == -1 or lo == -1:
raise EOFException()
return chr((hi << 8) | lo)
def readDouble(self):
data = self._read_bytes(8)
return _struct.unpack(">d", data)[0]
def readFloat(self):
data = self._read_bytes(4)
return _struct.unpack(">f", data)[0]
def readInt(self):
data = self._read_bytes(4)
return _struct.unpack(">i", data)[0]
def readLine(self):
result = []
while True:
ch = self.read()
if ch == -1:
break
if ch == 0x0A:
break
if ch == 0x0D:
next_ch = self.read()
if next_ch != 0x0A:
self.seek(self.getFilePointer() - 1)
break
result.append(chr(ch))
return "".join(result) if result else None
def readLong(self):
data = self._read_bytes(8)
return _struct.unpack(">q", data)[0]
def readShort(self):
data = self._read_bytes(2)
return _struct.unpack(">h", data)[0]
def readUnsignedByte(self):
v = self.read()
if v == -1:
raise EOFException()
return v & 0xFF
def readUnsignedShort(self):
hi = self.read()
lo = self.read()
if hi == -1 or lo == -1:
raise EOFException()
return ((hi & 0xFF) << 8) | (lo & 0xFF)
def readUTF(self):
length = self.readUnsignedShort()
data = self._read_bytes(length)
return data.decode("utf-8")
def write(self, b=None, off=None, length=None):
if b is None:
return
if isinstance(b, int):
self._file.write(bytes([b & 0xFF]))
else:
if off is not None and length is not None:
self._file.write(bytes(b[off:off+length]))
else:
self._file.write(bytes(b))
def writeBoolean(self, v):
self.write(int(v))
def writeByte(self, v):
self.write(v & 0xFF)
def writeBytes(self, s):
for ch in str(s):
self.write(ord(ch) & 0xFF)
def writeChar(self, v):
self.write((v >> 8) & 0xFF)
self.write(v & 0xFF)
def writeChars(self, s):
for ch in str(s):
self.writeChar(ord(ch))
def writeDouble(self, v):
data = _struct.pack(">d", v)
self._file.write(data)
def writeFloat(self, v):
data = _struct.pack(">f", v)
self._file.write(data)
def writeInt(self, v):
data = _struct.pack(">i", v)
self._file.write(data)
def writeLong(self, v):
data = _struct.pack(">q", v)
self._file.write(data)
def writeShort(self, v):
data = _struct.pack(">h", v)
self._file.write(data)
def writeUTF(self, s):
encoded = str(s).encode("utf-8")
self.writeShort(len(encoded))
self._file.write(encoded)
def _read_bytes(self, n):
data = self._file.read(n)
if len(data) < n:
raise EOFException()
return data
def setLength(self, new_length):
pos = self.getFilePointer()
self._file.truncate(new_length)
if pos > new_length:
self.seek(new_length)
def close(self):
if not self._closed:
self._closed = True
self._file.close()
def getChannel(self):
return self._file
def flush(self):
self._file.flush()
def __del__(self):
self.close()