There are different modes you can open a file with, specified by the mode parameter. These include:
`'r'` - reading mode. The default. It allows you only to read the
file, not to modify it. When using this mode the file must exist.
`'w'` - writing mode. It will create a new file if it does not exist, otherwise will erase the file and allow you to write to it.
`'a'` - append mode. It will write data to the end of the file. It does not erase the file, and the file must exist for this mode.
`'rb'` - reading mode in binary. This is similar to `r` except that the reading is forced in binary mode. This is also a default choice.
`'r+'` - reading mode plus writing mode at the same time. This allows you to read and write into files at the same time without having to use `r` and `w`.
`'rb+'` - reading and writing mode in binary. The same as `r+` except the data is in binary
`'wb'` - writing mode in binary. The same as `w` except the data is in binary.
`'w+'` - writing and reading mode. The exact same as `r+` but if the file does not exist, a new one is made. Otherwise, the file is overwritten.
`'wb+'` - writing and reading mode in binary mode. The same as `w+` but the data is in binary.
`'ab'` - appending in binary mode. Similar to `a` except that the data is in binary.
`'a+'` - appending and reading mode. Similar to `w+` as it will create a new file if the file does not exist. Otherwise, the file pointer is at the end of the file if it exists.
`'ab+'` - appending and reading mode in binary. The same as `a+` except that the data is in binary.
Python 3 added a new mode for exclusive creation so that you will not accidentally truncate or overwrite and existing file.
'x' - open for exclusive creation, will raise FileExistsError if the file already exists
'xb' - open for exclusive creation writing mode in binary. The same as x except the data is in binary.
'x+' - reading and writing mode. Similar to w+ as it will create a new file if the file does not exist. Otherwise, will raise FileExistsError.
'xb+' - writing and reading mode. The exact same as x+ but the data is binary
x
x+
Read
✘
✔
Write
✔
✔
Creates file
✔
✔
Erases file
✘
✘
Initial position
Start
Start
Allow one to write your file open code in a more pythonic manner:
try:withopen("fname","r")as fout:# Work with your open fileexcept FileExistsError:# Your error handling goes here
In Python 2 you would have done something like
import os.path
if os.path.isfile(fname):withopen("fname","w")as fout:# Work with your open fileelse:# Your error handling goes here
Reading a file line-by-line
The simplest way to iterate over a file line-by-line:
withopen('myfile.txt','r')as fp:for line in fp:print(line)
readline() allows for more granular control over line-by-line iteration. The example below is equivalent to the one above:
withopen('myfile.txt','r')as fp:whileTrue:
cur_line = fp.readline()# If the result is an empty stringif cur_line =='':# We have reached the end of the filebreakprint(cur_line)
Using the for loop iterator and readline() together is considered bad practice.
More commonly, the readlines() method is used to store an iterable collection of the file's lines:
withopen("myfile.txt","r")as fp:
lines = fp.readlines()for i inrange(len(lines)):print("Line "+str(i)+": "+ line)
This would print the following:
Line 0: hello
Line 1: world
Iterate files (recursively)
To iterate all files, including in sub directories, use os.walk:
import os
for root, folders, files in os.walk(root_dir):for filename in files:print root, filename
root_dir can be "." to start from current directory, or any other path to start from.
If you also wish to get information about the file, you may use the more efficient method os.scandir(opens new window) like so:
for entry in os.scandir(path):ifnot entry.name.startswith('.')and entry.is_file():print(entry.name)
Getting the full contents of a file
The preferred method of file i/o is to use the with keyword. This will ensure the file handle is closed once the reading or writing has been completed.
It is also possible to use the print statement to write to a file. The mechanics are different in Python 2 vs Python 3, but the concept is the same in that you can take the output that would have gone to the screen and send it to a file instead.
withopen('fred.txt','w')as outfile:
s ="I'm Not Dead Yet!"print(s)# writes to stdoutprint(s,file= outfile)# writes to outfile#Note: it is possible to specify the file parameter AND write to the screen#by making sure file ends up with a None value either directly or via a variable
myfile =Noneprint(s,file= myfile)# writes to stdoutprint(s,file=None)# writes to stdout
In Python 2 you would have done something like
outfile =open('fred.txt','w')
s ="I'm Not Dead Yet!"print s # writes to stdoutprint>> outfile, s # writes to outfile
Unlike using the write function, the print function does automatically add line breaks.
import errno
try:withopen(path)as f:# File existsexcept IOError as e:# Raise the exception if it is not ENOENT (No such file or directory)if e.errno != errno.ENOENT:raise# No such file or directory
This will also avoid race-conditions if another process deleted the file between the check and when it is used. This race condition could happen in the following cases:
Using the `os` module:
import os
os.path.isfile('/path/to/some/file.txt')
To check whether a given path exists or not, you can follow the above EAFP procedure, or explicitly check the path:
import os
path ="/home/myFiles/directory1"if os.path.exists(path):## Do stuff
Random File Access Using mmap
Using the mmap(opens new window) module allows the user to randomly access locations in a file by mapping the file into memory. This is an alternative to using normal file operations.
import mmap
withopen('filename.ext','r')as fd:# 0: map the whole file
mm = mmap.mmap(fd.fileno(),0)# print characters at indices 5 through 10print mm[5:10]# print the line starting from mm's current positionprint mm.readline()# write a character to the 5th index
mm[5]='a'# return mm's position to the beginning of the file
mm.seek(0)# close the mmap object
mm.close()
Copying contents of one file to a different file
withopen(input_file,'r')as in_file,open(output_file,'w')as out_file:for line in in_file:
out_file.write(line)
So let's suppose you want to iterate only between some specific lines of a file
You can make use of itertools for that
This will read through the lines 13 to 20 as in python indexing starts from 0. So line number 1 is indexed as 0
As can also read some extra lines by making use of the next() keyword here.
And when you are using the file object as an iterable, please don't use the readline() statement here as the two techniques of traversing a file are not to be mixed together
Replacing text in a file
import fileinput
replacements ={'Search1':'Replace1','Search2':'Replace2'}for line in fileinput.input('filename.txt', inplace=True):for search_for in replacements:
replace_with = replacements[search_for]
line = line.replace(search_for, replace_with)print(line, end='')
Checking if a file is empty
>>>import os
>>> os.stat(path_to_file).st_size ==0
or
>>>import os
>>> os.path.getsize(path_to_file)>0
However, both will throw an exception if the file does not exist. To avoid having to catch such an error, do this:
import os
defis_empty_file(fpath):return os.path.isfile(fpath)and os.path.getsize(fpath)>0
the path to your file or, if the file is in the working directory, the filename of your file
access_mode
a string value that determines how the file is opened
buffering
an integer value used for optional line buffering
Remarks
Avoiding the cross-platform Encoding Hell
When using Python's built-in open(), it is best-practice to always pass the encoding argument, if you intend your code to be run cross-platform.
The Reason for this, is that a system's default encoding differs from platform to platform.
While linux systems do indeed use utf-8 as default, this is not necessarily true for MAC and Windows.
To check a system's default encoding, try this:
import sys
sys.getdefaultencoding()
from any python interpreter.
Hence, it is wise to always sepcify an encoding, to make sure the strings you're working with are encoded as what you think they are, ensuring cross-platform compatiblity.
withopen('somefile.txt','r', encoding='UTF-8')as f:for line in f:print(line)