Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing to a file in Python inserts null bytes

I'm writing a todo list program. It keeps a file with a thing to do per line, and lets the user add or delete items. The problem is that for some reason, I end up with a lot of zero bytes at the start of the file, even though the item is correctly deleted. I'll show you a couple of screenshots to make sure I'm making myself clear.

This is the file in Notepad++ before running the program:

Normal todo list

This is the file after deleting item 3 (counting from 1):

Item 3 is gone, but there are NUL bytes

This is the relevant code. The actual program is bigger, but running just this part triggers the error.

import os
TODO_FILE = r"E:\javi\code\Python\todo-list\src\todo.txt"

def del_elems(f, delete):
    """Takes an open file and either a number or a list of numbers, and deletes the
    lines corresponding to those numbers (counting from 1)."""
    if isinstance(delete, int):
        delete = [delete]
    lines = f.readlines()
    f.truncate(0)
    counter = 1
    for line in lines:
        if counter not in delete:
            f.write(line)
        counter += 1

f = open(TODO_FILE, "r+")
del_elems(f, 3)
f.close()

Could you please point out where's the mistake?

like image 203
Javier Avatar asked Jun 12 '10 22:06

Javier


People also ask

How do you write nulls bytes?

However, in Modified UTF-8 the null character is encoded as two bytes: 0xC0, 0x80. This allows the byte with the value of zero, which is now not used for any character, to be used as a string terminator.

What is %00 null byte?

Null Byte Injection is an active exploitation technique used to bypass sanity checking filters in web infrastructure by adding URL-encoded null byte characters (i.e. %00, or 0x00 in hex) to the user-supplied data.

What is null byte in hex?

Null is 00 in hexadecimal.


3 Answers

It looks to me like you're forgetting to rewind your file stream. After f.truncate(0), add f.seek(0). Otherwise, I think your next write will try to start at the position from which you left off, filling in null bytes on its way there.

(Notice that the number of null characters in your example equals the number of characters in your deleted lines plus a carriage-return and line-feed character for each one.)

like image 121
ʇsәɹoɈ Avatar answered Sep 21 '22 22:09

ʇsәɹoɈ


From the Python manual:

file.truncate([size])
Truncate the file's size. If the optional size argument is present, the file is truncated to (at most) that size. The size defaults to the current position. The current file position is not changed. Note that if a specified size exceeds the file’s current size, the result is platform-dependent: possibilities include that the file may remain unchanged, increase to the specified size as if zero-filled, or increase to the specified size with undefined new content. Availability: Windows, many Unix variants.

You are truncating the file and then writing item1 and item2 at the former end of the file. Everything before that ends up padded with 0 bytes.

f.seek(0)

Call this to reset the file position after the truncate.

like image 36
John Kugelman Avatar answered Sep 20 '22 22:09

John Kugelman


Take the hint. Don't do this.

In the olden days (30 years ago -- seriously) we "updated" files with complex add/change/delete logic.

Nowadays, life is simpler if you write programs that

  1. Read the entire file into memory.

  2. Work on the objects in memory.

  3. Write the objects to a file periodically and when the user wants to save.

It's faster and simpler. Use pickle to dump your objects to a file. Don't mess with "records" or any attempt to change a file "in place".

If you really think you need SQL capabilities (Insert, Update, Delete) then use SQLite. It's more reliable than what you're attempting to do.

like image 37
S.Lott Avatar answered Sep 21 '22 22:09

S.Lott