Search code examples
pythonpython-3.xfilereadfiletruncate

Python 3: Idiomatic way to delete last char in file


Is there an idiomatic way to do this? I just upgraded from Python 2 to Python 3 and I'm trying to port my script, and I gotta say I'm not impressed. From what I can tell, my code gets to go

from this

# Not allowed by Python 3 anymore without being in binary mode.
card_names_file.seek(-1, os.SEEK_END)
if card_names_file.read() == ',':
    card_names_file.truncate()

to this

# Go to end of file just to get position index. lawl.
card_names_file.seek(0, os.SEEK_END)
# Create a temporary just to store said index. More lawl.
eof = card_names_file.tell()
# Index one from the back. ugh. w/e, that's fine.
card_names_file.seek(eof - 1, os.SEEK_SET)

# Oh wait, .read() will advance my pointer. Oh hey Python 3 doesn't let me
# use .peek() either. Fantastic. I'll have to read this...
if card_names_file.read() == ',':
    # Then go back to where I was by indexing from front AGAIN
    card_names_file.seek(eof - 1, os.SEEK_SET)
    # Then remove last character.
    card_names_file.truncate()

This is the dumbest code I've almost ever seen and I've spent 2 and a half hours so far trying to delete a character from the back of a file, and this looks like a hack.

The alternative is that I have code that looks like this

# open file
with open(file, a+)
    # do stuff

# open same file
with open(file, w+b)
    # do different stuff

But I can't actually get that to work either.


Solution

  • Underlying buffer does have a peek() method you were looking for, so:

    f = open('FILE', 'a+')
    f.seek(f.seek(0, os.SEEK_END) - 1)
    # or with the same effect you can also:
    os.lseek(f.fileno(), -1, os.SEEK_END)
    # Actually in append mode we could just seek by -1 from where we are
    # (cursor at the end after opening)
    f.tell()  # just to see...
    f.buffer.peek(1)
    f.tell()  # ...still where we were
    

    Alternatively, you could also use os.pread(). For instance:

    os.pread(f.fileno(), 1, os.fstat(f.fileno()).st_size - 1)
    

    It's not very idiomatic as in relying on higher level abstraction accessing files, but I'd invoke: "Although practicality beats purity."