Home > Software engineering >  Does read() function affect the file content?
Does read() function affect the file content?

Time:12-24

I have a .txt file with a fixed format:

Tudo Bom;Static and Ben El Tavori;5:13;
I Gotta Feeling;The Black Eyed Peas;4:05;
Instrumental;Unknown;4:15;
Paradise;Coldplay;4:23;
Where is the love?;The Black Eyed Peas;4:13;

I'm trying to replace the name of the song in the third line with a new name.

I've written a function called my_mp4_playlist which takes two parameters: The first one is the file path (string) and the second is the new song name (string).

I'm trying to first get the file content with the read() function and then loop the file lines till the third one and split the line with ";".

My problem is that when I use the read() function, there's nothing to split, and when I don't read, the split works just fine.

The code (not finished yet) is looking like this:

def my_mp4_playlist(file_path, new_song):
    with open(file_path, "r ") as f:  # we using r  for reading and writing and not overriding ALL text in the file
        file_source = f.read()
        third_line_list = []
        for i, line in enumerate(f, 0):
            if i == 2:
                print(line.split(";"))
                third_line_list = line.split(";")
                break    

The output of the print statement is just nothing. But if I'm commenting the f.read() line the output is:

['Instrumental', 'Unknown', '4:15', '\n']

Why is this happening? I'd like to know in a more general way and not a specific solution to my problem.

CodePudding user response:

https://pynative.com/python-file-seek/

When reading files in most programming languages, the file object maintains a 'cursor' (also called 'pointer') to keep track of the portions of the file that have already been read and where to start reading on subsequent read requests. This cursor starts at the first byte of a file and advances forward until it reaches the end of the file.

For example, when you read a file line-by-line, the file object starts at the current location of the cursor, reads the line, then advances the cursor to the end of the line it just read. It knows to stop reading when the cursor reaches the end of the file.

So on your initial call to f.read(), you are reading the entire file, so the cursor gets placed at the end of the file. On the subsequent call to enumerate (f,0), since the cursor is at the end of the file, there is nothing left to read in the file so the loop is effectively skipped.

When you comment out f.read(), since you have not yet read the file before enumerate (f,0), the file cursor remains at the beginning of the file, so that's why the loop works when you comment out f.read()

If you need to keep file_source = f.read() (file_source looks to be unused, so I'm not sure of its purpose) then you need to reset the file cursor to the beginning of the file before the next read. You can do this with f.seek(0) which will place the cursor back at the 0th byte in the file.

Alternatively, since the entire contents of the file is now in file_source, you no longer need to read from the file directly.

CodePudding user response:

When you open the file, the current read position is set to 0. The issue here is that after you read whole content of the file using read() method, the read position moves to the end of the file. So when you try to read content of the file once again in this enumerator then there is nothing left to read, because read position is already at the end of the file.

If you comment the read() method then read position will be still at 0 when enumerator is called so there is something to read.

To solve this you can reset the read position by using the seek() method just before calling enumerator and set it to position 0.

f.seek(0)
for i, line in enumerate(f, 0):

You can also use whole file content that was read by read() method in enumerator instead of reading it from file. This is even preferable solution because you don't need to read file once again from disk but reuse what is already in memory. Something like this should do that:

for i, line in enumerate(file_source.splitlines(), 0):
  • Related