I am trying to open a file read it's content and write to it by using the contents that were read earlier. I am opening the file in 'a+' mode. I can't use 'r+' mode since it won't create a file if it doesn't exist.
-
If you know how to solve it using `r+`, why don't precede that part with a check if the file exists using `os.path.exists()`, and [create](https://stackoverflow.com/questions/12654772/create-empty-file-using-python) it if it doesn't. – Thymen Dec 12 '20 at 14:45
-
1@Thymen I am doing it now, but I was wondering how can you do this. There will be some scenarios where it will be useful. – TheWhiteFang Dec 12 '20 at 16:03
2 Answers
a+
will put the pointer in the end of the file.
You can save it with tell()
for later writing.
Then use seek(0,0)
to return to file beginning for reading.

- 5,570
- 2
- 14
- 30
-
I can't find any documentation for these functions, can you point me to it? Thanks. – TheWhiteFang Dec 12 '20 at 16:09
-
i mistakenly called it like in C fseek and ftell. in python it is just `seek` and `tell`. added doc links – Lior Cohen Dec 12 '20 at 16:16
-
In 'a+' mode they manipulate only the read pointer. I want to control where I am writing. – TheWhiteFang Dec 13 '20 at 06:14
-
There is no read pointer or write pointer. Just pointer from where read or write begins – Lior Cohen Dec 13 '20 at 16:52
-
Default open
Using the default a(+)
option, it is not possible, as provided in the documentation:
''mode is an optional string that specifies the mode in which the file is opened. It defaults to 'r' which means open for reading in text mode. Other common values are 'w' for writing (truncating the file if it already exists), 'x' for creating and writing to a new file, and 'a' for appending (which on some Unix systems, means that all writes append to the end of the file regardless of the current seek position).''
Alternative
Using the default open, this is not possible.However we can of course create our own file handler, that will create a file in r
and r+
mode when it doesn't exists.
A minimal working example that works exactly like open(filename, 'r+', *args, **kwargs)
, would be:
import os
class FileHandler:
def __init__(self, filename, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
self.filename = filename
self.mode = mode
self.kwargs = dict(buffering=buffering, encoding=encoding, errors=errors, newline=newline, closefd=closefd)
if self.kwargs['buffering'] is None:
del self.kwargs['buffering']
def __enter__(self):
if self.mode.startswith('r') and not os.path.exists(self.filename):
with open(self.filename, 'w'): pass
self.file = open(self.filename, self.mode, **self.kwargs)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
Now when you use the following code:
with FileHandler("new file.txt", "r+") as file:
file.write("First line\n")
file.write("Second line\n")
file.seek(0, 0)
file.write("Third line\n")
It will generate a new file new file.txt
, when it doesn't exists, with the context:
Third line
Second line
If you would use the open
you will receive a FileNotFoundError
, if the file doesn't exists.
Notes
- I am only creating a new file when the mode starts with an
r
, all other files are handled as would be by the normalopen
function. - For some reason passing
buffering=None
, directly to theopen
function crashes it with anTypeError: an integer is required (got type NoneType)
, therefore I had to remove it from the key word arguments if it wasNone
. Even though it is the default argument according to the documentation (if any one knows why, please tell me)
Edit
The above code didn't handle the following cases:
file = FileHandler("new file.txt", "r+")
file.seek(0, 0)
file.write("Welcome")
file.close()
In order to support all of the open
use cases, the above class can be adjusted by using __getattr__
as follows:
import os
class FileHandler:
def __init__(self, filename, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
self.filename = filename
self.mode = mode
self.kwargs = dict(buffering=buffering, encoding=encoding, errors=errors, newline=newline, closefd=closefd)
if self.kwargs['buffering'] is None:
del self.kwargs['buffering']
if self.mode.startswith('r') and not os.path.exists(self.filename):
with open(self.filename, 'w'): pass
self.file = open(self.filename, self.mode, **self.kwargs)
def __enter__(self):
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
def __getattr__(self, item):
if hasattr(self.file, item):
return getattr(self.file, item)
raise AttributeError(f"{type(self).__name__}, doesn't have the attribute {item!r}")

- 2,089
- 1
- 9
- 13