Remove very last character in file

前端 未结 7 1779
说谎
说谎 2020-11-29 08:00

After looking all over the Internet, I\'ve come to this.

Let\'s say I have already made a text file that reads: Hello World

Well, I want to remo

相关标签:
7条回答
  • 2020-11-29 08:23

    here is a dirty way (erase & recreate)... i don't advice to use this, but, it's possible to do like this ..

    x = open("file").read()
    os.remove("file")
    open("file").write(x[:-1])
    
    0 讨论(0)
  • 2020-11-29 08:28

    Use fileobject.seek() to seek 1 position from the end, then use file.truncate() to remove the remainder of the file:

    import os
    
    with open(filename, 'rb+') as filehandle:
        filehandle.seek(-1, os.SEEK_END)
        filehandle.truncate()
    

    This works fine for single-byte encodings. If you have a multi-byte encoding (such as UTF-16 or UTF-32) you need to seek back enough bytes from the end to account for a single codepoint.

    For variable-byte encodings, it depends on the codec if you can use this technique at all. For UTF-8, you need to find the first byte (from the end) where bytevalue & 0xC0 != 0x80 is true, and truncate from that point on. That ensures you don't truncate in the middle of a multi-byte UTF-8 codepoint:

    with open(filename, 'rb+') as filehandle:
        # move to end, then scan forward until a non-continuation byte is found
        filehandle.seek(-1, os.SEEK_END)
        while filehandle.read(1) & 0xC0 == 0x80:
            # we just read 1 byte, which moved the file position forward,
            # skip back 2 bytes to move to the byte before the current.
            filehandle.seek(-2, os.SEEK_CUR)
    
        # last read byte is our truncation point, move back to it.
        filehandle.seek(-1, os.SEEK_CUR)
        filehandle.truncate()
    

    Note that UTF-8 is a superset of ASCII, so the above works for ASCII-encoded files too.

    0 讨论(0)
  • 2020-11-29 08:28

    In case you are not reading the file in binary mode, where you have only 'w' permissions, I can suggest the following.

    f.seek(f.tell() - 1, os.SEEK_SET)
    f.write('')
    

    In this code above, f.seek() will only accept f.tell() b/c you do not have 'b' access. then you can set the cursor to the starting of the last element. Then you can delete the last element by an empty string.

    0 讨论(0)
  • 2020-11-29 08:34
    with open(urfile, 'rb+') as f:
        f.seek(0,2)                 # end of file
        size=f.tell()               # the size...
        f.truncate(size-1)          # truncate at that size - how ever many characters
    

    Be sure to use binary mode on windows since Unix file line ending many return an illegal or incorrect character count.

    0 讨论(0)
  • 2020-11-29 08:34

    On a Linux system or (Cygwin under Windows). You can use the standard truncate command. You can reduce or increase the size of your file with this command.

    In order to reduce a file by 1G the command would be truncate -s 1G filename. In the following example I reduce a file called update.iso by 1G.

    Note that this operation took less than five seconds.

    chris@SR-ENG-P18 /cygdrive/c/Projects
    $ stat update.iso
      File: update.iso
      Size: 30802968576     Blocks: 30081024   IO Block: 65536  regular file
    Device: ee6ddbceh/4000177102d   Inode: 19421773395035112  Links: 1
    Access: (0664/-rw-rw-r--)  Uid: (1052727/   chris)   Gid: (1049089/Domain Users)
    Access: 2020-06-12 07:39:00.572940600 -0400
    Modify: 2020-06-12 07:39:00.572940600 -0400
    Change: 2020-06-12 07:39:00.572940600 -0400
     Birth: 2020-06-11 13:31:21.170568000 -0400
    
    chris@SR-ENG-P18 /cygdrive/c/Projects
    $ truncate -s -1G update.iso
    
    chris@SR-ENG-P18 /cygdrive/c/Projects
    $ stat update.iso
      File: update.iso
      Size: 29729226752     Blocks: 29032448   IO Block: 65536  regular file
    Device: ee6ddbceh/4000177102d   Inode: 19421773395035112  Links: 1
    Access: (0664/-rw-rw-r--)  Uid: (1052727/   chris)   Gid: (1049089/Domain Users)
    Access: 2020-06-12 07:42:38.335782800 -0400
    Modify: 2020-06-12 07:42:38.335782800 -0400
    Change: 2020-06-12 07:42:38.335782800 -0400
     Birth: 2020-06-11 13:31:21.170568000 -0400
    

    The stat command tells you lots of info about a file including its size.

    0 讨论(0)
  • 2020-11-29 08:35

    Accepted answer of Martijn is simple and kind of works, but does not account for text files with:

    • UTF-8 encoding containing non-English characters (which is the default encoding for text files in Python 3)
    • one newline character at the end of the file (which is the default in Linux editors like vim or gedit)

    If the text file contains non-English characters, neither of the answers provided so far would work.

    What follows is an example, that solves both problems, which also allows removing more than one character from the end of the file:

    import os
    
    
    def truncate_utf8_chars(filename, count, ignore_newlines=True):
        """
        Truncates last `count` characters of a text file encoded in UTF-8.
        :param filename: The path to the text file to read
        :param count: Number of UTF-8 characters to remove from the end of the file
        :param ignore_newlines: Set to true, if the newline character at the end of the file should be ignored
        """
        with open(filename, 'rb+') as f:
            last_char = None
    
            size = os.fstat(f.fileno()).st_size
    
            offset = 1
            chars = 0
            while offset <= size:
                f.seek(-offset, os.SEEK_END)
                b = ord(f.read(1))
    
                if ignore_newlines:
                    if b == 0x0D or b == 0x0A:
                        offset += 1
                        continue
    
                if b & 0b10000000 == 0 or b & 0b11000000 == 0b11000000:
                    # This is the first byte of a UTF8 character
                    chars += 1
                    if chars == count:
                        # When `count` number of characters have been found, move current position back
                        # with one byte (to include the byte just checked) and truncate the file
                        f.seek(-1, os.SEEK_CUR)
                        f.truncate()
                        return
                offset += 1
    

    How it works:

    • Reads only the last few bytes of a UTF-8 encoded text file in binary mode
    • Iterates the bytes backwards, looking for the start of a UTF-8 character
    • Once a character (different from a newline) is found, return that as the last character in the text file

    Sample text file - bg.txt:

    Здравей свят
    

    How to use:

    filename = 'bg.txt'
    print('Before truncate:', open(filename).read())
    truncate_utf8_chars(filename, 1)
    print('After truncate:', open(filename).read())
    

    Outputs:

    Before truncate: Здравей свят
    After truncate: Здравей свя
    

    This works with both UTF-8 and ASCII encoded files.

    0 讨论(0)
提交回复
热议问题