Unexpected output due to file.readline() when using 'a+'

65 Views Asked by At

Initially, I have a text file named new_file which stores 1\n2\n3\n4\n5\n

I execute the following python program :

f = open('new_file', 'a+')

f.write('\n'.join(str(i) for i in range(1, 6)))
f.seek(0)

print(f.readlines())

f.seek(0)
f.write("\nFinal Line")

print(f.readlines())

f.close()

I expected the program to first add 1\n2\n3\n4\n5 to new_file, then print ['1\n', '2\n', '3\n', '4\n', '5\n', '1\n', '2\n', '3\n', '4\n', '5'], then finally add \nFinal Line to new_file and print ['1\n', '2\n', '3\n', '4\n', '5\n', '1\n', '2\n', '3\n', '4\n', '5\n', 'Final line']

The changes to the file are as I expected, but what the program prints is this :

['1\n', '2\n', '3\n', '4\n', '5\n', '1\n', '2\n', '3\n', '4\n', '5']
['1\n', '2\n', '3\n', '4\n', '5\n', '1\n', '2\n', '3\n', '4\n', '5']

Why does this happen?

2

There are 2 best solutions below

2
SIGHUP On

As per the documentation for fopen if the file is opened in a+ mode "Output is always appended to the end of the file". Therefore you need to seek(0) immediately before the final call to readlines() in order to see the entire contents.

import os

try:
    os.remove("new_file")
except FileNotFoundError:
    pass

with open('new_file', 'a+') as f:
    f.write('\n'.join(str(i) for i in range(1, 6)))
    f.seek(0)
    print(f.readlines())
    # file pointer is now at EOF for reading
    f.write("\nFinal Line")
    # seek to BOF
    f.seek(0)
    print(f.readlines())

Output:

['1\n', '2\n', '3\n', '4\n', '5']
['1\n', '2\n', '3\n', '4\n', '5\n', 'Final Line']
7
Jamie On

You should be using w+ mode instead of a+, and your second seek statement is on the wrong side of the second write statement.

To achieve your desired results your code should be:

f = open('new_file', 'w+')

f.write('\n'.join(str(i) for i in range(1, 6)))
f.seek(0)

print(f.readlines())


f.write("\nFinal Line")
f.seek(0)

print(f.readlines())

f.close()

The output is:

['1\n', '2\n', '3\n', '4\n', '5']
['1\n', '2\n', '3\n', '4\n', '5\n', 'Final Line']

If you must use a+ mode then your code should be:

import os

f = open('new_file2', 'a+')

f.write('\n'.join(str(i) for i in range(1, 6)))
f.seek(0)

print(f.readlines())


f.write("\nFinal Line")
f.seek(0)

print(f.readlines())

f.close()
os.remove(f.name)

And the output will also be:

['1\n', '2\n', '3\n', '4\n', '5']
['1\n', '2\n', '3\n', '4\n', '5\n', 'Final Line']