Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
r+ mode in files
#1
Hi Viewer,

I know r+ mode is used for reading and writing to a file. What I find strange is as soon as I open the file and then write to the file instead of reading, it writes from the first position. If I read first and then write to the file, it writes at the end of the file. Please see the code below:

test.data (created the file before running the code):

Welcome to Python line 1
Welcome to Python line 2
Welcome to Python line 3
Welcome to Python line 4

with open(file = 'test.data', mode = 'r+', encoding = 'utf-8') as fp:
    fp.write('new line\n')
The file gets modified as follows,

Output:
new line Python 1 Welcome to Python 2 Welcome to Python 3 Welcome to Python 4
Now I re-create the original text file test.data. And now when I read just first line and then write to it, it writes to the end of the file.

with open(file = 'test.data', mode = 'r+', encoding = 'utf-8') as fp:
    print(fp.readline())
    fp.write('new line\n')
    print(fp.readline())
The text file after the program executes:

Output:
Welcome to Python 1 Welcome to Python 2 Welcome to Python 3 Welcome to Python 4 new line
The following is the output from the above line of code:

Output:
Welcome to Python 1
I am unable to understand why Python does write to the file at the end of the file instead of at the location of the file pointer.

Please help.

Thanks.
Reply
#2
There are six access modes (that I know of):

1. 'r' Read only: the default
2. 'w' Write: Create a new file or overwrite the contents of an existing file.
3. 'a' Append: Write data to the end of an existing file.
4. 'r+' Both read and write to an existing file. The file pointer will be at the beginning of the file.
5. 'w+' Both read and write to a new file or overwrite the contents of an existing file.
6. 'a+' Both read and write to an existing file or create a new file. The file pointer will be at the end of the file.

Maybe this will be of help?
Sig:
>>> import this

The UNIX philosophy: "Do one thing, and do it well."

"The danger of computers becoming like humans is not as great as the danger of humans becoming like computers." :~ Konrad Zuse

"Everything should be made as simple as possible, but not simpler." :~ Albert Einstein
Reply
#3
I understand your confusion. r+ is confusing. When you write, were do you write?

The logical answer is that writing starts at the file pointer. When you open a file with r+, the file pointer starts at 0. When you read a file, the file pointer moves to the end. This explain why writing happens at the start of the file when you open a file with r+ and do a write. It also explains why you write at the end of a file when you open a file, do a read(), then do a write.

What isn't so well explained is what happens if you open a file, read one line, and do a write.

When I run this:
with open("test.txt", "w") as file:
    file.write("One\nTwo\nThree\n")

with open("test.txt", "r+") as file:
    file.readline()
    print(file.tell())
    file.write("Four\n")
The file pointer is 5:
Output:
5
But it creates this file:
Output:
One Two Three Four
This looks like the file pointer was 13,, not 5, for the write()

And look at what happens when I set the file pointer before doing a write.
with open("test.txt", "w") as file:
    file.write("One\nTwo\nThree\n")

with open("test.txt", "r+") as file:
    file.readline()
    file.seek(file.tell())  # Move file pointer to the reported file pointer location.
    file.write("Four\n")
It creates this file:
Output:
One Four hree
Here the write() starts at the file position.

Bizarre!

I cannot find anything documenting the expected behavior in Python, so I looked at C++ documetnation. I found this:

https://cplusplus.com/reference/cstdio/fopen/

Quote:For files open for update (those which include a "+" sign), on which both input and output operations are allowed, the stream shall be flushed (fflush) or repositioned (fseek, fsetpos, rewind) before a reading operation that follows a writing operation. The stream shall be repositioned (fseek, fsetpos, rewind) before a writing operation that follows a reading operation (whenever that operation did not reach the end-of-file).

This doesn't explicitly say where it will be repositioned, but implies it is repositioned to the end of the file.

I think that the takeaway is that you should never write anywhere except at the end of a file, and that r+ is an odd mode.
Reply
#4
(Feb-14-2023, 03:24 PM)rob101 Wrote: There are six access modes (that I know of):

1. 'r' Read only: the default
2. 'w' Write: Create a new file or overwrite the contents of an existing file.
3. 'a' Append: Write data to the end of an existing file.
4. 'r+' Both read and write to an existing file. The file pointer will be at the beginning of the file.
5. 'w+' Both read and write to a new file or overwrite the contents of an existing file.
6. 'a+' Both read and write to an existing file or create a new file. The file pointer will be at the end of the file.

Maybe this will be of help?

Thank you for sparing time to respond to my question.
rob101 likes this post
Reply
#5
(Feb-14-2023, 09:03 PM)deanhystad Wrote: I understand your confusion. r+ is confusing. When you write, were do you write?

The logical answer is that writing starts at the file pointer. When you open a file with r+, the file pointer starts at 0. When you read a file, the file pointer moves to the end. This explain why writing happens at the start of the file when you open a file with r+ and do a write. It also explains why you write at the end of a file when you open a file, do a read(), then do a write.

What isn't so well explained is what happens if you open a file, read one line, and do a write.

When I run this:
with open("test.txt", "w") as file:
    file.write("One\nTwo\nThree\n")

with open("test.txt", "r+") as file:
    file.readline()
    print(file.tell())
    file.write("Four\n")
The file pointer is 5:
Output:
5
But it creates this file:
Output:
One Two Three Four
This looks like the file pointer was 13,, not 5, for the write()

And look at what happens when I set the file pointer before doing a write.
with open("test.txt", "w") as file:
    file.write("One\nTwo\nThree\n")

with open("test.txt", "r+") as file:
    file.readline()
    file.seek(file.tell())  # Move file pointer to the reported file pointer location.
    file.write("Four\n")
It creates this file:
Output:
One Four hree
Here the write() starts at the file position.

Bizarre!

I cannot find anything documenting the expected behavior in Python, so I looked at C++ documetnation. I found this:

https://cplusplus.com/reference/cstdio/fopen/

Quote:For files open for update (those which include a "+" sign), on which both input and output operations are allowed, the stream shall be flushed (fflush) or repositioned (fseek, fsetpos, rewind) before a reading operation that follows a writing operation. The stream shall be repositioned (fseek, fsetpos, rewind) before a writing operation that follows a reading operation (whenever that operation did not reach the end-of-file).

This doesn't explicitly say where it will be repositioned, but implies it is repositioned to the end of the file.

I think that the takeaway is that you should never write anywhere except at the end of a file, and that r+ is an odd mode.

Yes I have noticed it as well. If we seek first and then write it properly writes to the position where we want it to write. Like you said it is strange.

Thank you for going thru various documentations on my behalf and taking time to respond back to my question. I tried my best in looking it up and could not find it anywhere.

Thanks.
Reply
#6
You could use fd.seek() to jump to the end of the file:

with open("file.txt", "w") as fd:
    for line in range(1, 5):
        fd.write(f"Welcome to Python line {line}\n")


with open("file.txt", "r+") as fd:
    print("Position after open:", fd.tell())
    fd.seek(0, 2)
    print("Position after seek:", fd.tell())
    fd.write("Hello World\n")


with open("file.txt", "r") as fd:
    print(fd.read())
Docs: https://docs.python.org/3/library/io.htm...OBase.seek
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  things that work in terminal mode but not in sublime mode alok 4 2,899 Aug-11-2021, 07:02 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020