Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you read first line from file with open(fname, 'a+')?

I want to be able to open a file, append some text to the end, and then read only the first line. I know exactly how long the first line of the file is, and the file is large enough that I don't want to read it into memory all at once. I've tried using:

with open('./output files/log.txt', 'a+') as f:

    f.write('This is example text')

    content = f.readline()
    print(content)

but the print statement is blank. When I try using open('./output files/log.txt') or open('./output files/log.txt', 'r+') instead of open('./output files/log.txt', 'a+') this works so I know it has to do with the 'a+ argument. My problem is that I have to append to the file. How can I append to the file and still get the first line without using something like

with open('./output files/log.txt', 'a+') as f_1:

    f.write('This is example text')

    with open('./output files/log.txt') as f_2:
        content = f_2.readline()
        print(content)
like image 280
user144153 Avatar asked Mar 11 '23 15:03

user144153


2 Answers

When you open a file with the append flag a, it moves the file descriptor's pointer to the end of the file, so that the write call will add to the end of the file.

The readline() function reads from the current pointer of the file until the next '\n' character it reads. So when you open a file with append, and then call readline, it will try to read a line starting from the end of the file. This is why your print call is coming up blank.

You can see this in action by looking at where the file object is currently pointing, using the tell() function.

To read the first line, you'd have to make sure the file's pointer is back at the beginning of the file, which you can do using the seek function. seek takes two arguments: offset and from_what. If you omit the second argument, offset is taken from the beginning of the file. So to jump to the beginning of the file, do: seek(0).

If you want to jump back to the end of the file, you can include the from_what option. from_what=2 means take the offset from the end of the file. So to jump to the end: seek(0, 2).


Demonstration of file pointers when opened in append mode:

Example using a text file that looks like this:

the first line of the file
and the last line

Code:

with open('example.txt', 'a+') as fd:
    print fd.tell() # at end of file
    fd.write('example line\n')
    print fd.tell() # at new end of the file after writing

    # jump to the beginning of the file:
    fd.seek(0)
    print fd.readline()

    # jump back to the end of the file
    fd.seek(0, 2)
    fd.write('went back to the end')

console output:

45
57
the first line of the file

new contents of example.txt:

the first line of the file
and the last line
example line
went back to the end


Edit: added jumping back to end of file

like image 151
xgord Avatar answered Mar 19 '23 06:03

xgord


You need to go back to the start of the file using seek(0), like so:

with open('./output files/log.txt', 'a+') as f_1:
    f_1.write('This is example text')
    f_1.seek(0)
    print(f_1.readline())
like image 45
Nick Avatar answered Mar 19 '23 05:03

Nick