I/O Objects¶
pcapkit.corekit.io contains
SeekableReader, a seekable customisation of
io.BufferedReader, and the stream proxies:
PeekableStream, which adds peek to a seekable
stream, and NamedStream, which gives a stream a
name; advance(), which moves a stream past
more octets than one read or seek can take; and
can_seek(), which tells whether a stream really seeks.
- class pcapkit.corekit.io.SeekableReader(raw, buffer_size=io.DEFAULT_BUFFER_SIZE, buffer_save=False, buffer_path=None, *, stream_closing=True)[source]¶
Bases:
BufferedReaderSeekable buffered reader.
A buffered binary stream providing higher-level access to a readable, non seekable
RawIOBaseraw binary stream. It inheritsBufferedIOBase.When reading data from this object, a larger amount of data may be requested from the underlying raw stream, and kept in an internal buffer. The buffered data can then be returned directly on subsequent reads.
The constructor creates a
BufferedReaderfor the given readablerawstream andbuffer_size. Ifbuffer_sizeis omitted,DEFAULT_BUFFER_SIZEis used.- Parameters:
Changed in version 1.5.0:
truncate()raisesUnsupportedOperation, aswritable()returnsFalse(#645). A refusedseek()leaves the position where it was, and a position the lookback buffer has dropped raises instead of reading from it (#643, #644).Removed in version 1.5.0:
writeable(), a misspelling that never overrodeio.IOBase.writable(); usewritable()(#645).- property raw: RawIOBase¶
The underlying raw stream (a
RawIOBaseinstance) thatBufferedIOBasedeals with. This is not part of theBufferedIOBaseAPI and may not exist on some implementations.
- read(size=-1, /)[source]¶
Read and return
sizebytes, or ifsizeis not given or negative, until EOF or if the read call would block in non-blocking mode.- Return type:
- read1(size=-1, /)[source]¶
Read and return up to
sizebytes with only one call on the raw stream. If at least one byte is buffered, only buffered bytes are returned. Otherwise, one raw stream read call is made.- Return type:
- readinto(b, /)[source]¶
Read bytes into a pre-allocated, writable bytes-like object
band return the number of bytes read. For example,bmight be abytearray.Like
read(), multiple reads may be issued to the underlying raw stream, unless the latter is interactive.A
BlockingIOErroris raised if the underlying raw stream is in non blocking-mode, and has no data available at the moment.- Return type:
- readinto1(b, /)[source]¶
Read bytes into a pre-allocated, writable bytes-like object
b, using at most one call to the underlying raw stream’sread()(orreadinto()) method. Return the number of bytes read.A
BlockingIOErroris raised if the underlying raw stream is in non blocking-mode, and has no data available at the moment.- Return type:
- readable()[source]¶
Return
Trueif the stream can be read from. IfFalse,read()will raiseOSError.- Return type:
- readline(size=-1, /)[source]¶
Read and return one line from the stream. If
sizeis specified, at mostsizebytes will be read.The line terminator is always
b'\n'for binary files; for text files, thenewlineargument toopen()can be used to select the line terminator(s) recognized.- Return type:
- readlines(hint=-1, /)[source]¶
Read and return a list of lines from the stream.
hintcan be specified to control the number of lines read: no more lines will be read if the total size (in bytes/characters) of all lines so far exceedshint.hintvalues of0or less, as well asNone, are treated as no hint.Note that it’s already possible to iterate on file objects using
for line in file: ...without callingfile.readlines().
- writable()[source]¶
Return
Trueif the stream supports writing. IfFalse,write()andtruncate()will raiseOSError.- Return type:
- write(b, /)[source]¶
Write the given bytes-like object,
b, and return the number of bytes written (always equal to the length ofbin bytes, since if the write fails anOSErrorwill be raised). Depending on the actual implementation, these bytes may be readily written to the underlying stream, or held in a buffer for performance and latency reasons.When in non-blocking mode, a
BlockingIOErroris raised if the data needed to be written to the raw stream but it couldn’t accept all the data without blocking.The caller may release or mutate
bafter this method returns, so the implementation should only accessbduring the method call.- Return type:
- seekable()[source]¶
Return
Trueif the stream supports random access. IfFalse,seek(),tell()andtruncate()will raiseOSError.- Return type:
- seek(offset, whence=io.SEEK_SET, /)[source]¶
Change the stream position to the given byte
offset.offsetis interpreted relative to the position indicated bywhence. The default value forwhenceisSEEK_SET. Values forwhenceare:SEEK_SETor0- start of the stream (the default);offsetshould be zero or positiveSEEK_CURor1- current stream position;offsetmay be negativeSEEK_ENDor2- end of the stream;offsetis usually negative
Return the new absolute position.
Note
The target is computed, then validated, and only then written to
_tell. A branch that assigned the position before deciding whether to accept it would leave a refused seek having moved it anyway, with the resync below – the one thing that puts the buffer’s cursor back in step – skipped on the way out. A caller that catches the error and reasonably takes the position to be unchanged would then read from the rejected offset instead, silently and without a second error.The negative check applies to every
whence, rather than onlySEEK_SETlooking at its offset. An absolute position below zero cannot exist under any of them, and it is not the same failure as a position that has merely slid out of the window – which is ordinary, and recoverable withbuffer_save=True. Reporting the first asnegative seek valuekeeps the two distinguishable, and, being a property of the position rather than of the window, it holds with a saved buffer as well, which is exempt from the window check and would otherwise return a negative position as if the seek had worked.A non-seekable stream has no end until it is over, so
SEEK_ENDis as far as_read_ahead()reads past the position:_read_ahead_sizeoctets, a buffer’s worth by default, or to the real end if that comes first. The frame readers measure what is left this way, and the engines set that size to the next record, so a record is measured whole, however long. The buffer’s far edge will not do as the end: once the buffer has filled it is just how far the stream has been read, so the first record ending there would be taken for the end of the capture (#1586). The read slides the buffer, so a position before the oneSEEK_ENDwas sought from may then be refused, as_read_ahead()says.- Return type:
- truncate(size=None, /)[source]¶
Resize the stream to the given
sizein bytes (or the current position ifsizeis not specified).- Raises:
UnsupportedOperation – Always, since the reader is not writable.
- Return type:
Note
io.IOBase.writable()gates this method as well aswrite()– “IfFalse,write()andtruncate()will raiseOSError” – andwritable()here returnsFalse, so refusing is what the contract asks for. It is also what CPython’s own read-only buffered readers do: both the acceleratedio.BufferedReaderand the pure-Python_pyio.BufferedReaderraiseio.UnsupportedOperation, the latter from_BufferedIOMixin.truncate’s_checkWritable()(#645).Resizing the lookback buffer is reachable internally, as
_truncate_buffer(). It never touches the underlying stream – it resizes a private lookback window – which is why it stays, under a private name.
- close()[source]¶
Flush and close this stream. This method has no effect if the file is already closed. Once the file is closed, any operation on the file (e.g. reading or writing) will raise a
ValueError.As a convenience, it is allowed to call this method more than once; only the first call, however, will have an effect.
- flush()[source]¶
Flush the write buffers of the stream if applicable. This does nothing for read-only and non-blocking streams.
- peek(size=0)[source]¶
Return bytes from the stream without advancing the position.
At most one single read on the raw stream is done to satisfy the call. The number of bytes returned may be less or more than requested.
- Return type:
- detach()[source]¶
Separate the underlying raw stream from the buffer and return it.
After the raw stream has been detached, the buffer is in an unusable state.
Some buffers, like
BytesIO, do not have the concept of a single raw stream to return from this method. They raiseUnsupportedOperation.- Return type:
- fileno()[source]¶
Return the underlying file descriptor (an integer) of the stream if it exists. An
OSErroris raised if the IO object does not use a file descriptor.- Return type:
- isatty()[source]¶
Return
Trueif the stream is interactive (i.e., connected to a terminal/tty device).- Return type:
- _read_ahead_size: int¶
Octets
seek()reads past the position to find the end of the stream; the buffer size by default.
- _read_ahead()[source]¶
Read the stream to
_read_ahead_sizeoctets past the position.- Returns:
that many octets past the position, or the end of the stream if it ended first.
seek()takes this as the end.- Return type:
Note
The buffer slides forward to make the room, so after this only the last
_buffer_sizeless_read_ahead_sizeoctets before the position can still be sought back to – none, at the default – unlessbuffer_savekeeps them. It grows instead of sliding past the position itself, so a record longer than the buffer is held whole, as its reader seeks back to its first octet; a bogus length grows it only as far as the stream goes. A live stream holds the reader here until the octets arrive, which is why the engines set_read_ahead_sizeto the record they are about to read.
- _truncate_buffer(size=None, /)[source]¶
Resize the lookback buffer to the given
sizein bytes (or the current position ifsizeis not specified). The current stream position isn’t changed. This resizing can extend or reduce the current buffer size. In case of extension, the new area is zero-filled. The new buffer size is returned.Note
Nothing here writes to the underlying stream –
write()raises – so what this resizes is the buffer, not the stream behind it. That is whytruncate()refuses (#645) while this remains: the operation is a private-window one, not anio.IOBasewrite. The buffer is a sliding window over a stream that cannot be seeked: its octet 0 sits at absolute offset_buffer_set, its content occupies[0:_buffer_cur], and everything past that is padding never read.As for which octets survive: an extension appends its zero octets at the tail, the new area being by definition the region past the old end. A reduction below the content keeps the most recent
sizeoctets and advances_buffer_setpast the ones it drops, because what this holds is lookback: the octets it can still answer for are the ones just read, and the stream is already beyond them. Padding is never kept in preference to content either way.Advancing
_buffer_setis what keeps_buffer_set + _buffer_curequal to how far the stream has actually been consumed, whichseek()relies on to decide whether it may read ahead to fill a gap. A reduction that shrank the window without moving its base would leave that sum short of the stream, and the next forwardseek()would splice in octets from the wrong absolute offset without complaining.Octets dropped by a reduction are gone for good, since the stream cannot be rewound to re-supply them. A position left among them is then before the window, which
seek()refuses as it refuses any other.- Return type:
- class pcapkit.corekit.io.PeekableStream(stream)[source]¶
Bases:
objectGive a seekable binary stream without
peekone.Extractorand the PCAP-NG engine read ahead withpeek, whichio.BufferedReaderhas and a plaintyping.IOsuch asio.BytesIOdoes not (#1506). The read-ahead is a read and a seek back, and every other attribute is the stream’s own. It is not anio.IOBase, so it has no finaliser that could close the caller’s stream behind their back (#610).Copying and pickling follow the stream (#1524).
copy.copy()gives a second proxy over the same stream, so the two share one position.copy.deepcopy()andpicklecopy the stream too, so they work exactly when the stream itself can be deep-copied or pickled at that protocol: anio.BytesIOpickles at protocol 2 and above, and an open file not at all.
- class pcapkit.corekit.io.NamedStream(stream, name)[source]¶
Bases:
objectRead-only proxy that gives a stream the
nameattribute.pcapfile.savefile.load_savefiledereferencesinput_file.nameunconditionally, on the way into its trace helper. That is fine for theBufferedReaderExtractornormally holds, but not for theSeekableReaderit substitutes when the caller supplied a non-seekable stream – that class exposes noname, so the load would fail withAttributeErrorbefore a single byte was read.- name¶
Name of the underlying stream.
- pcapkit.corekit.io.advance(file, count, /)[source]¶
Move
fileforward bycountoctets, however many one read or seek can take.- Parameters:
A frame reader asks for a record no further than one read can go,
sys.maxsize, so a record the file really holds past that is read only as far as the limit; the next record still starts where this one declares it ends (#1975). A seekable stream gets there by relative seeks, none longer thansys.maxsize, and may land past its end, as an absolute seek would. ASeekableReader, or a stream that cannot seek – including one that only says it can, as a Windows pipe does (#2108) – reads the octets and discards them, no more thanREAD_CHUNKat a time, and stops at the end of the stream: aSeekableReaderseek reads at most a buffer’s worth past what it holds, so a longer one would stop short of the target.
- pcapkit.corekit.io.can_seek(stream)[source]¶
Whether
streamcan really seek, rather than only saying it can.On Windows before CPython 3.16, a pipe reports
seekable()and itsseeksilently does nothing (#2097), so the answer is trusted only for a regular file, or for a stream with no descriptor to ask.