Reading data from a file and writing to a file

Creating a file

In Python, to create a file, you need to open it in write mode ('w', 'wb') or append mode ('a', 'ab').

f2 = open("text2.txt", 'w')

The open() function returns a file object.

Without 'b', a text file is created, which is a stream of characters. With 'b' is the file containing the byte stream.

In Python, there is also the 'x' or 'xb' mode. In this mode, it is checked whether there is a file. If a file with this name already exists, it will not be created. In the 'w' mode, the file is recreated, the old one is lost.

>>> f1 = open('text1.txt', 'w')
>>> f2 = open('text1.txt', 'x')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: 'text1.txt'
>>> f3 = open('text1.txt', 'w')

Reading data from a file

If the second argument is not passed to the open() function, the file is treated as a text file and opened for reading.

An attempt to open a non-existent file to read causes an error.

>>> f = open("text10.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'text10.txt'

You can catch an exception by using the try-except operator.

>>> try:
...     f = open("text10.txt")
... except IOError:
...     print ("No file")
...
No file

To get all the data from a file, you can use the read() method of the file object, after opening the file for reading. In this case, the file object is changed and it will not be possible to retrieve the data from it again.

>>> f = open("text.txt")
>>> f
<_io.TextIOWrapper name='text.txt' mode='r' encoding='UTF-8'>
>>> fd = f.read()
>>> fd1 = f.read()
>>> fd
'Hello\n\tOne\n   Two\nThree Four\nSix!\n'
>>> fd1
''

If the file was opened in text mode, the read() method returns a string. In case of binary mode, an object of type bytes is returned.

>>> f = open('text.txt', 'rb')
>>> content = f.read()
>>> type(content)
<class 'bytes'>
>>> content
b'HelloHello'
>>> content[0]
72
>>> chr(content[0])
'H'

The read() method can take one argument indicating the number of characters (if the file was opened as a text file) or bytes (if the file was opened as a binary file) to read.

>>> f = open("text.txt")
>>> fd = f.read(10)
>>> fd1 = f.read(5)
>>> fd
'Hello\n\tOne'
>>> fd1
'\n   T'

readline() allows to receive data line by line.

>>> f = open("text.txt")
>>> f.readline()
'Hello\n'
>>> f.readline()
'\tOne\n'
>>> f.readline()
'   Two\n'

It takes an argument that is the number of bytes or characters.

>>> f.readline(3)
'Thr'
>>> f.readline(3)
'ee '
>>> f.readline(3)
'Fou'
>>> f.readline(3)
'r\n'
>>> f.readline(5)
'Five!'
>>> f.readline(5)
'\n'

To read data from a file line by line, it is recommended to use a for loop:

>>> f = open('text.txt')
>>> for line in f:
...     print(line, end='')
...
Hello!
The second line.
>>> f.close()

readlines() reads the lines and places them in the list.

>>> f = open("text.txt")
>>> fd = f.readlines()
>>> fd
['Hello\n', '\tOne\n', '   Two\n', 'Three Four\n', 'Six!\n']

It accepts the number of characters, but reads the string to the end.

>>> f = open("text.txt")
>>> fd = f.readlines(3)
>>> fd
['Hello\n']
>>> fd1 = f.readlines(6)
>>> fd1
['\tOne\n', '   Two\n']>

Writing data to a file

You can write data to a file using the write() method, which returns the number of characters or bytes written.

>>> ft = open('text1.txt', 'w')
>>> fb = open('text2.txt', 'wb')
>>> t = 'Привет Мир!'
>>> b = b'Hello World!'
>>> type(t), type(b)
(<class 'str'>, <class 'bytes'>)
>>> ft.write(t)
11
>>> fb.write(b)
12
>>> ft.close()
>>> fb.close()
>>>
>>> import os.path
>>> os.path.getsize('text1.txt')
20
>>> os.path.getsize('text2.txt')
12
>>> open('text2.txt').read()
'Hello World!'

If the data written to a text file is not a string, then it must first be converted to a string.

>>> a = [1, 2, 3, 4]
>>> sa = str(a)
>>> sa
'[1, 2, 3, 4]'
>>> f = open('mylist.txt', 'w')
>>> f.write(sa)
12
>>> f.close()
>>>
>>> with open('mylist.txt') as f:
...     sa = f.read()
...
>>> sa
'[1, 2, 3, 4]'
>>> list(sa)  # bad idea
['[', '1', ',', ' ', '2', ',', ' ', '3', ',', ' ', '4', ']']
>>> a = [int(i) for i in sa if i.isdigit()]
>>> a
[1, 2, 3, 4]

Using the writelines() method, you can write an iteration to a file.

>>> a = [1,2,3,4,5,6,7,8,9,0]
>>> f = open("text2.txt",'w')
>>> f.writelines("%s\n" % i for i in a)
>>> f.close()
>>> open("text2.txt").read()
'1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n'
>>> print(open("text2.txt").read())
1
2
3
4
5
6
7
8
9
0

Changing the position in the file

The tell() method returns the current position in the file. The position can be changed using the seek() method.

>>> f = open('text.txt')
>>> f.tell()
0
>>> f.readline()
'Hello!\n'
>>> f.tell()
7
>>> f.seek(5)
5
>>> f.read(1)
'!'
>>> f.tell()
6
>>> f.read()
'\nThe second line.\n'
>>> f.read()
''
>>> f.seek(0)
0
>>> f.read()
'Hello!\nThe second line.\n'

In the case of binary files, you can pass a second argument to the seek() method. This argument specifies from where the offset specified in the first argument is performed: 0 (default) - from the beginning of the file, 1 - from the current position, 2 - from the end.

>>> f = open('text.txt', 'rb')
>>> f.read()
b'Hello!\nThe second line.\n'
>>> f.seek(-6, 2)
18
>>> f.read(4)
b'line'
>>> f.seek(0)
0
>>> f.read(5)
b'Hello'
>>> f.seek(2, 1)
7
>>> f.read(3)
b'The'

Closing a file

In Python, you should close the file to free up system resources. This is done using the close() method of the file object.

Using closed (not a constant, but a so-called data descriptor) it is checked whether the file is closed or not.

>>> f = open('text.txt')
>>> f.closed
False
>>> f.close()
>>> f.closed
True

It is considered good practice to use the with operator when processing file objects. After the with body has finished running, the file will be closed automatically. When with is called, a context manager is created, which is a special object. Thanks to it, global states are saved and restored, resources are blocked and unblocked, files are closed, etc.

>>> with open('text.txt') as f:
...     print(f.read())
...
HelloHello
>>> f.closed
True
>>> with open('text.txt') as fr, open('text2.txt', 'w') as fw:
...     fw.write(fr.read())
...
10
>>> fw.closed
True
>>> with (
...     open('text.txt') as fr,
...     open('text2.txt', 'w') as fw,
... ):
...     fw.write(fr.read())
...
10

Binary files

The example of copying of an image:

>>> f1 = open('flag.png', 'rb')
>>> f2 = open('flag2.png', 'wb')
>>> f2.write(f1.read())
446
>>> f1.close()
>>> f2.close()

The struct module allows you to convert data to a binary form and vice versa.

>>> f = open('text3.txt', 'wb')
>>> f.write('3')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
>>> d = struct.pack('>i',3)
>>> d
b'\x00\x00\x00\x03'
>>> f.write(d)
4
>>> f.close()
>>> f = open('text3.txt')
>>> d = f.read()
>>> d
'\x00\x00\x00\x03'
>>> struct.unpack('>i',d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
>>> f = open('text3.txt', 'rb')
>>> d = f.read()
>>> d
b'\x00\x00\x00\x03'
>>> struct.unpack('>i',d)
(3,)