hbutils.file.stream

Stream Utilities for Seekable File Objects.

This module provides helper utilities for managing the state of seekable file streams, including preserving cursor position, obtaining stream size, and checking end-of-file conditions. The helpers work for both text and binary streams that implement the standard Python file API.

The module contains the following public utilities:

  • keep_cursor() - Preserve the current cursor position within a context.

  • getsize() - Retrieve the size of a stream in bytes or characters.

  • is_eof() - Check whether the stream cursor is at the end-of-file.

Note

All functions in this module require seekable file-like objects. Non-seekable streams will raise OSError.

Example:

>>> import io
>>> from hbutils.file.stream import keep_cursor, getsize, is_eof
>>>
>>> with io.BytesIO(b'\xde\xad\xbe\xef') as f:
...     print(getsize(f))
...     with keep_cursor(f):
...         _ = f.read(2)
...     print(f.tell(), is_eof(f))
4
0 False

__all__

hbutils.file.stream.__all__ = ['keep_cursor', 'getsize', 'is_eof']

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

keep_cursor

hbutils.file.stream.keep_cursor(file: TextIO | BinaryIO) ContextManager[None][source]

Keep the cursor of the given file within a with-block.

This context manager saves the current cursor position of a file stream before entering the context and restores it when exiting, regardless of any operations performed within the context.

Parameters:

file (Union[TextIO, BinaryIO]) – File whose cursor needs to be preserved.

Returns:

A context manager that preserves the file cursor position.

Return type:

ContextManager[None]

Raises:

OSError – If the given file is not seekable.

Examples::
>>> import io
>>> from hbutils.file import keep_cursor
>>>
>>> with io.BytesIO(b'\xde\xad\xbe\xef') as file:
...     with keep_cursor(file):
...         print(file.read(2))
...     with keep_cursor(file):  # still from 0
...         print(file.read())
...
...     _ = file.read(2)
...     with keep_cursor(file):  # now from 2
...         print(file.read(1))
...     with keep_cursor(file):  # still from 2
...         print(file.read())
b'\xde\xad'
b'\xde\xad\xbe\xef'
b'\xbe'
b'\xbe\xef'

Note

Only seekable streams can use keep_cursor().

getsize

hbutils.file.stream.getsize(file: TextIO | BinaryIO) int[source]

Get the size of the given file stream.

This function attempts to retrieve the file size by first trying to use os.stat() on the file descriptor. If that fails (e.g., for in-memory streams), it seeks to the end of the file to determine the size, then restores the original cursor position.

Parameters:

file (Union[TextIO, BinaryIO]) – File whose size needs to be accessed.

Returns:

File’s size in bytes (for binary files) or characters (for text files).

Return type:

int

Raises:

OSError – If the given file is not seekable.

Examples::
>>> import io
>>> from hbutils.file import getsize
>>>
>>> with io.BytesIO(b'\xde\xad\xbe\xef') as file:
...     print(getsize(file))
4
>>> with open('README.md', 'r') as file:
...     print(getsize(file))
2582

Note

Only seekable streams can use getsize().

is_eof

hbutils.file.stream.is_eof(file: TextIO | BinaryIO) bool[source]

Check if the file cursor is at the end of the file.

This function determines whether the current cursor position is at the end of the file by comparing the current position (from tell()) with the total file size (from getsize()).

Parameters:

file (Union[TextIO, BinaryIO]) – File to be checked.

Returns:

True if the cursor is at the end of file, False otherwise.

Return type:

bool

Raises:

OSError – If the given file is not seekable.

Examples::
>>> import io
>>> from hbutils.file import is_eof
>>>
>>> with io.BytesIO(b'\xde\xad\xbe\xef') as file:
...     print(file.tell(), is_eof(file))
...     _ = file.read(2)
...     print(file.tell(), is_eof(file))
...     _ = file.read(2)
...     print(file.tell(), is_eof(file))
0 False
2 False
4 True
>>> with open('README.md', 'r') as file:
...     print(file.tell(), is_eof(file))
...     _ = file.read(100)
...     print(file.tell(), is_eof(file))
...     _ = file.read()
...     print(file.tell(), is_eof(file))
0 False
100 False
2582 True

Note

Only seekable streams can use is_eof().