tail

Cameron Simpson cs at cskk.id.au
Sun May 1 18:18:39 EDT 2022


On 01May2022 18:55, Marco Sulla <Marco.Sulla.Python at gmail.com> wrote:
>Something like this is OK?
[...]
>def tail(f):
>    chunk_size = 100
>    size = os.stat(f.fileno()).st_size

I think you want os.fstat().

>    positions = iter(range(size, -1, -chunk_size))
>    next(positions)

I was wondering about the iter, but this makes sense. Alternatively you 
could put a range check in the for-loop.

>    chunk_line_pos = -1
>    pos = 0
>
>    for pos in positions:
>        f.seek(pos)
>        chars = f.read(chunk_size)
>        chunk_line_pos = chars.rfind(b"\n")
>
>        if chunk_line_pos != -1:
>            break

Normal text file _end_ in a newline. I'd expect this to stop immediately 
at the end of the file.

>    if chunk_line_pos == -1:
>        nbytes = pos
>        pos = 0
>        f.seek(pos)
>        chars = f.read(nbytes)
>        chunk_line_pos = chars.rfind(b"\n")

I presume this is because unless you're very lucky, 0 will not be a 
position in the range(). I'd be inclined to avoid duplicating this code 
and special case and instead maybe make the range unbounded and do 
something like this:

    if pos < 0:
        pos = 0
    ... seek/read/etc ...
    if pos == 0:
        break

around the for-loop body.

>    if chunk_line_pos == -1:
>        line_pos = pos
>    else:
>        line_pos = pos + chunk_line_pos + 1
>    f.seek(line_pos)
>    return f.readline()
>
>This is simply for one line and for utf8.

And anything else where a newline is just an ASCII newline byte (10) and 
can't be mistaken otherwise. So also ASCII and all the ISO8859-x single 
byte encodings. But as Chris has mentioned, not for other encodings.

Seems sane. I haven't tried to run it.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Python-list mailing list