Watch Now This tutorial has a related video course created past the Real Python squad. Spotter it together with the written tutorial to deepen your understanding: Reading and Writing Files in Python

One of the most common tasks that y'all can do with Python is reading and writing files. Whether information technology's writing to a simple text file, reading a complicated server log, or even analyzing raw byte data, all of these situations require reading or writing a file.

In this tutorial, you'll acquire:

  • What makes up a file and why that's important in Python
  • The basics of reading and writing files in Python
  • Some bones scenarios of reading and writing files

This tutorial is mainly for beginner to intermediate Pythonistas, but there are some tips in here that more advanced programmers may appreciate also.

What Is a File?

Earlier nosotros can go into how to work with files in Python, information technology's important to empathise what exactly a file is and how modern operating systems handle some of their aspects.

At its core, a file is a face-to-face set of bytes used to store data. This information is organized in a specific format and tin be anything as simple as a text file or as complicated equally a program executable. In the cease, these byte files are then translated into binary i and 0 for easier processing by the computer.

Files on most modern file systems are composed of iii master parts:

  1. Header: metadata nigh the contents of the file (file name, size, blazon, and so on)
  2. Data: contents of the file equally written past the creator or editor
  3. Finish of file (EOF): special character that indicates the stop of the file
The file format with the header on top, data contents in the middle and the footer on the bottom.

What this data represents depends on the format specification used, which is typically represented past an extension. For case, a file that has an extension of .gif almost probable conforms to the Graphics Interchange Format specification. There are hundreds, if non thousands, of file extensions out at that place. For this tutorial, you'll only deal with .txt or .csv file extensions.

File Paths

When you access a file on an operating system, a file path is required. The file path is a string that represents the location of a file. It's cleaved upwardly into 3 major parts:

  1. Binder Path: the file binder location on the file organization where subsequent folders are separated by a forward slash / (Unix) or backslash \ (Windows)
  2. File Name: the bodily proper noun of the file
  3. Extension: the stop of the file path pre-pended with a menses (.) used to indicate the file blazon

Here's a quick example. Let's say you have a file located within a file structure like this:

                                / │ ├── path/ |   │ │   ├── to/ │   │   └── cats.gif │   │ │   └── dog_breeds.txt | └── animals.csv                              

Permit'southward say you wanted to access the cats.gif file, and your current location was in the same binder every bit path. In order to access the file, y'all need to go through the path folder and then the to binder, finally arriving at the cats.gif file. The Folder Path is path/to/. The File Name is cats. The File Extension is .gif. So the full path is path/to/cats.gif.

Now let's say that your current location or current working directory (cwd) is in the to folder of our example binder structure. Instead of referring to the cats.gif past the total path of path/to/cats.gif, the file tin be simply referenced past the file proper noun and extension cats.gif.

                                / │ ├── path/ |   │ |   ├── to/  ← Your current working directory (cwd) is here |   │   └── cats.gif  ← Accessing this file |   │ |   └── dog_breeds.txt | └── animals.csv                              

But what about dog_breeds.txt? How would y'all access that without using the full path? You can use the special characters double-dot (..) to move i directory up. This means that ../dog_breeds.txt will reference the dog_breeds.txt file from the directory of to:

                                / │ ├── path/  ← Referencing this parent folder |   │ |   ├── to/  ← Current working directory (cwd) |   │   └── cats.gif |   │ |   └── dog_breeds.txt  ← Accessing this file | └── animals.csv                              

The double-dot (..) can be chained together to traverse multiple directories above the current directory. For case, to access animals.csv from the to folder, you would employ ../../animals.csv.

Line Endings

One problem often encountered when working with file data is the representation of a new line or line catastrophe. The line catastrophe has its roots from dorsum in the Morse Code era, when a specific pro-sign was used to communicate the cease of a transmission or the end of a line.

Later, this was standardized for teleprinters by both the International Arrangement for Standardization (ISO) and the American Standards Association (ASA). ASA standard states that line endings should use the sequence of the Carriage Render (CR or \r) and the Line Feed (LF or \n) characters (CR+LF or \r\due north). The ISO standard withal allowed for either the CR+LF characters or just the LF graphic symbol.

Windows uses the CR+LF characters to indicate a new line, while Unix and the newer Mac versions use just the LF graphic symbol. This can cause some complications when you're processing files on an operating organisation that is different than the file'south source. Here'southward a quick example. Let'south say that we examine the file dog_breeds.txt that was created on a Windows system:

                                Pug\r\n Jack Russell Terrier\r\n English Springer Spaniel\r\north German Shepherd\r\north Staffordshire Bull Terrier\r\n Cavalier King Charles Spaniel\r\northward Golden Retriever\r\north W Highland White Terrier\r\north Boxer\r\northward Border Terrier\r\n                              

This same output will be interpreted on a Unix device differently:

                                Pug\r \due north Jack Russell Terrier\r \northward English Springer Spaniel\r \n German Shepherd\r \n Staffordshire Bull Terrier\r \n Cavalier King Charles Spaniel\r \n Golden Retriever\r \n West Highland White Terrier\r \n Boxer\r \n Border Terrier\r \north                              

This tin make iterating over each line problematic, and you may need to account for situations like this.

Graphic symbol Encodings

Another common problem that you may face is the encoding of the byte information. An encoding is a translation from byte data to human readable characters. This is typically done by assigning a numerical value to represent a character. The two most common encodings are the ASCII and UNICODE Formats. ASCII can only store 128 characters, while Unicode can contain upwards to i,114,112 characters.

ASCII is actually a subset of Unicode (UTF-8), meaning that ASCII and Unicode share the same numerical to character values. It'south of import to note that parsing a file with the incorrect character encoding can lead to failures or misrepresentation of the grapheme. For example, if a file was created using the UTF-8 encoding, and you endeavor to parse information technology using the ASCII encoding, if at that place is a character that is exterior of those 128 values, then an error volition be thrown.

Opening and Closing a File in Python

When you desire to work with a file, the commencement affair to do is to open up it. This is done by invoking the open() born function. open up() has a single required argument that is the path to the file. open up() has a unmarried return, the file object:

                                            file                =                open up                (                'dog_breeds.txt'                )                          

Afterwards you open a file, the next thing to larn is how to close it.

It's important to remember that information technology's your responsibleness to shut the file. In almost cases, upon termination of an awarding or script, a file will be closed eventually. Notwithstanding, there is no guarantee when exactly that will happen. This can pb to unwanted beliefs including resource leaks. It's also a best do within Python (Pythonic) to make sure that your lawmaking behaves in a way that is well divers and reduces whatsoever unwanted behavior.

When you're manipulating a file, at that place are two means that you can use to ensure that a file is closed properly, fifty-fifty when encountering an error. The first way to close a file is to employ the endeavour-finally block:

                                            reader                =                open                (                'dog_breeds.txt'                )                try                :                # Further file processing goes here                finally                :                reader                .                close                ()                          

If you lot're unfamiliar with what the try-finally cake is, check out Python Exceptions: An Introduction.

The second mode to close a file is to utilise the with statement:

                                            with                open up                (                'dog_breeds.txt'                )                as                reader                :                # Farther file processing goes here                          

The with statement automatically takes care of closing the file in one case it leaves the with block, even in cases of error. I highly recommend that y'all utilise the with statement equally much as possible, as it allows for cleaner code and makes handling any unexpected errors easier for you lot.

Virtually likely, you'll likewise want to use the second positional statement, fashion. This statement is a string that contains multiple characters to correspond how yous want to open the file. The default and most common is 'r', which represents opening the file in read-only fashion as a text file:

                                            with                open                (                'dog_breeds.txt'                ,                'r'                )                equally                reader                :                # Farther file processing goes hither                          

Other options for modes are fully documented online, but the about ordinarily used ones are the following:

Character Meaning
'r' Open for reading (default)
'w' Open for writing, truncating (overwriting) the file first
'rb' or 'wb' Open in binary way (read/write using byte data)

Permit'due south become back and talk a little about file objects. A file object is:

"an object exposing a file-oriented API (with methods such equally read() or write()) to an underlying resource." (Source)

In that location are three dissimilar categories of file objects:

  • Text files
  • Buffered binary files
  • Raw binary files

Each of these file types are defined in the io module. Here'south a quick rundown of how everything lines up.

Text File Types

A text file is the nigh common file that y'all'll run across. Here are some examples of how these files are opened:

                                                  open                  (                  'abc.txt'                  )                  open up                  (                  'abc.txt'                  ,                  'r'                  )                  open                  (                  'abc.txt'                  ,                  'w'                  )                              

With these types of files, open up() will return a TextIOWrapper file object:

>>>

                                                  >>>                                    file                  =                  open                  (                  'dog_breeds.txt'                  )                  >>>                                    type                  (                  file                  )                  <form '_io.TextIOWrapper'>                              

This is the default file object returned by open up().

Buffered Binary File Types

A buffered binary file type is used for reading and writing binary files. Here are some examples of how these files are opened:

                                                  open up                  (                  'abc.txt'                  ,                  'rb'                  )                  open up                  (                  'abc.txt'                  ,                  'wb'                  )                              

With these types of files, open up() volition return either a BufferedReader or BufferedWriter file object:

>>>

                                                  >>>                                    file                  =                  open                  (                  'dog_breeds.txt'                  ,                  'rb'                  )                  >>>                                    type                  (                  file                  )                  <class '_io.BufferedReader'>                  >>>                                    file                  =                  open up                  (                  'dog_breeds.txt'                  ,                  'wb'                  )                  >>>                                    type                  (                  file                  )                  <class '_io.BufferedWriter'>                              

Raw File Types

A raw file type is:

"generally used as a depression-level building-block for binary and text streams." (Source)

It is therefore non typically used.

Here's an example of how these files are opened:

                                                  open up                  (                  'abc.txt'                  ,                  'rb'                  ,                  buffering                  =                  0                  )                              

With these types of files, open() will render a FileIO file object:

>>>

                                                  >>>                                    file                  =                  open                  (                  'dog_breeds.txt'                  ,                  'rb'                  ,                  buffering                  =                  0                  )                  >>>                                    type                  (                  file                  )                  <form '_io.FileIO'>                              

Reading and Writing Opened Files

One time y'all've opened upward a file, you lot'll desire to read or write to the file. First off, let'due south cover reading a file. In that location are multiple methods that can exist called on a file object to aid you out:

Method What It Does
.read(size=-1) This reads from the file based on the number of size bytes. If no statement is passed or None or -1 is passed, then the entire file is read.
.readline(size=-one) This reads at most size number of characters from the line. This continues to the finish of the line so wraps back around. If no argument is passed or None or -ane is passed, and so the entire line (or residue of the line) is read.
.readlines() This reads the remaining lines from the file object and returns them as a list.

Using the same dog_breeds.txt file you used in a higher place, allow'south go through some examples of how to use these methods. Hither's an example of how to open and read the entire file using .read():

>>>

                                            >>>                                with                open                (                'dog_breeds.txt'                ,                'r'                )                as                reader                :                >>>                                # Read & print the entire file                >>>                                print                (                reader                .                read                ())                Pug                Jack Russell Terrier                English Springer Spaniel                High german Shepherd                Staffordshire Bull Terrier                Cavalier King Charles Spaniel                Golden Retriever                West Highland White Terrier                Boxer                Border Terrier                          

Here's an case of how to read 5 bytes of a line each time using the Python .readline() method:

>>>

                                            >>>                                with                open                (                'dog_breeds.txt'                ,                'r'                )                as                reader                :                >>>                                # Read & impress the first 5 characters of the line 5 times                >>>                                print                (                reader                .                readline                (                v                ))                >>>                                # Notice that line is greater than the 5 chars and continues                >>>                                # down the line, reading 5 chars each time until the terminate of the                >>>                                # line and and then "wraps" effectually                >>>                                print                (                reader                .                readline                (                5                ))                >>>                                impress                (                reader                .                readline                (                5                ))                >>>                                print                (                reader                .                readline                (                5                ))                >>>                                print                (                reader                .                readline                (                five                ))                Pug                Jack                Russe                ll Te                rrier                          

Hither's an instance of how to read the unabridged file as a list using the Python .readlines() method:

>>>

                                            >>>                                f                =                open                (                'dog_breeds.txt'                )                >>>                                f                .                readlines                ()                # Returns a list object                ['Pug\n', 'Jack Russell Terrier\n', 'English Springer Spaniel\due north', 'High german Shepherd\n', 'Staffordshire Bull Terrier\n', 'Cavalier King Charles Spaniel\north', 'Golden Retriever\n', 'West Highland White Terrier\n', 'Boxer\n', 'Border Terrier\n']                          

The higher up case can also be done past using list() to create a list out of the file object:

>>>

                                            >>>                                f                =                open up                (                'dog_breeds.txt'                )                >>>                                list                (                f                )                ['Pug\n', 'Jack Russell Terrier\north', 'English Springer Spaniel\n', 'German Shepherd\due north', 'Staffordshire Balderdash Terrier\due north', 'Cavalier King Charles Spaniel\northward', 'Aureate Retriever\n', 'West Highland White Terrier\n', 'Boxer\northward', 'Border Terrier\n']                          

Iterating Over Each Line in the File

A common thing to do while reading a file is to iterate over each line. Hither's an case of how to apply the Python .readline() method to perform that iteration:

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    # Read and impress the unabridged file line by line                  >>>                                    line                  =                  reader                  .                  readline                  ()                  >>>                                    while                  line                  !=                  ''                  :                  # The EOF char is an empty string                  >>>                                    print                  (                  line                  ,                  end                  =                  ''                  )                  >>>                                    line                  =                  reader                  .                  readline                  ()                  Pug                  Jack Russell Terrier                  English language Springer Spaniel                  High german Shepherd                  Staffordshire Balderdash Terrier                  Cavalier King Charles Spaniel                  Golden Retriever                  West Highland White Terrier                  Boxer                  Edge Terrier                              

Another style you lot could iterate over each line in the file is to use the Python .readlines() method of the file object. Remember, .readlines() returns a list where each element in the list represents a line in the file:

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    for                  line                  in                  reader                  .                  readlines                  ():                  >>>                                    print                  (                  line                  ,                  cease                  =                  ''                  )                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  German Shepherd                  Staffordshire Bull Terrier                  Cavalier King Charles Spaniel                  Golden Retriever                  West Highland White Terrier                  Boxer                  Border Terrier                              

Yet, the above examples can be further simplified by iterating over the file object itself:

>>>

                                                  >>>                                    with                  open up                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    # Read and print the entire file line by line                  >>>                                    for                  line                  in                  reader                  :                  >>>                                    print                  (                  line                  ,                  stop                  =                  ''                  )                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  German Shepherd                  Staffordshire Bull Terrier                  Condescending King Charles Spaniel                  Golden Retriever                  West Highland White Terrier                  Boxer                  Border Terrier                              

This final approach is more Pythonic and can be quicker and more retention efficient. Therefore, information technology is suggested you use this instead.

Now let's dive into writing files. As with reading files, file objects have multiple methods that are useful for writing to a file:

Method What It Does
.write(string) This writes the string to the file.
.writelines(seq) This writes the sequence to the file. No line endings are appended to each sequence item. It'south upwardly to yous to add the appropriate line ending(south).

Here's a quick example of using .write() and .writelines():

                                                  with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  # Notation: readlines doesn't trim the line endings                  dog_breeds                  =                  reader                  .                  readlines                  ()                  with                  open                  (                  'dog_breeds_reversed.txt'                  ,                  'west'                  )                  as                  writer                  :                  # Alternatively you could use                  # author.writelines(reversed(dog_breeds))                  # Write the dog breeds to the file in reversed social club                  for                  brood                  in                  reversed                  (                  dog_breeds                  ):                  writer                  .                  write                  (                  breed                  )                              

Working With Bytes

Sometimes, yous may demand to piece of work with files using byte strings. This is done past calculation the 'b' character to the manner argument. All of the same methods for the file object apply. However, each of the methods look and render a bytes object instead:

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'rb'                  )                  every bit                  reader                  :                  >>>                                    print                  (                  reader                  .                  readline                  ())                  b'Pug\n'                              

Opening a text file using the b flag isn't that interesting. Let'south say nosotros have this beautiful picture of a Jack Russell Terrier (jack_russell.png):

A cute picture of a Jack Russell Terrier
Image: CC By 3.0 (https://creativecommons.org/licenses/by/iii.0)], from Wikimedia Commons

You can really open that file in Python and examine the contents! Since the .png file format is well defined, the header of the file is 8 bytes broken upwardly like this:

Value Interpretation
0x89 A "magic" number to indicate that this is the start of a PNG
0x50 0x4E 0x47 PNG in ASCII
0x0D 0x0A A DOS style line ending \r\n
0x1A A DOS way EOF graphic symbol
0x0A A Unix fashion line catastrophe \n

Sure enough, when you open up the file and read these bytes individually, you lot tin can encounter that this is indeed a .png header file:

>>>

                                                  >>>                                    with                  open                  (                  'jack_russell.png'                  ,                  'rb'                  )                  as                  byte_reader                  :                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  i                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  three                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  2                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  1                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  1                  ))                  b'\x89'                  b'PNG'                  b'\r\n'                  b'\x1a'                  b'\n'                              

A Full Case: dos2unix.py

Permit's bring this whole matter home and look at a full example of how to read and write to a file. The post-obit is a dos2unix like tool that will convert a file that contains line endings of \r\n to \n.

This tool is broken up into iii major sections. The first is str2unix(), which converts a cord from \r\due north line endings to \n. The second is dos2unix(), which converts a cord that contains \r\north characters into \northward. dos2unix() calls str2unix() internally. Finally, at that place's the __main__ block, which is called but when the file is executed as a script. Think of it as the main office found in other programming languages.

                                                  """                  A simple script and library to catechumen files or strings from dos like                  line endings with Unix similar line endings.                  """                  import                  argparse                  import                  os                  def                  str2unix                  (                  input_str                  :                  str                  )                  ->                  str                  :                  r                  """                                      Converts the string from \r\n line endings to \northward                                      Parameters                                      ----------                                      input_str                                      The string whose line endings will be converted                                      Returns                                      -------                                      The converted string                                      """                  r_str                  =                  input_str                  .                  replace                  (                  '                  \r\n                  '                  ,                  '                  \north                  '                  )                  return                  r_str                  def                  dos2unix                  (                  source_file                  :                  str                  ,                  dest_file                  :                  str                  ):                  """                                      Converts a file that contains Dos similar line endings into Unix like                                      Parameters                                      ----------                                      source_file                                      The path to the source file to be converted                                      dest_file                                      The path to the converted file for output                                      """                  # NOTE: Could add together file existence checking and file overwriting                  # protection                  with                  open                  (                  source_file                  ,                  'r'                  )                  every bit                  reader                  :                  dos_content                  =                  reader                  .                  read                  ()                  unix_content                  =                  str2unix                  (                  dos_content                  )                  with                  open                  (                  dest_file                  ,                  'westward'                  )                  as                  writer                  :                  author                  .                  write                  (                  unix_content                  )                  if                  __name__                  ==                  "__main__"                  :                  # Create our Argument parser and set its description                  parser                  =                  argparse                  .                  ArgumentParser                  (                  clarification                  =                  "Script that converts a DOS like file to an Unix like file"                  ,                  )                  # Add together the arguments:                  #   - source_file: the source file we desire to convert                  #   - dest_file: the destination where the output should go                  # Annotation: the apply of the argument type of argparse.FileType could                  # streamline some things                  parser                  .                  add_argument                  (                  'source_file'                  ,                  help                  =                  'The location of the source '                  )                  parser                  .                  add_argument                  (                  '--dest_file'                  ,                  assist                  =                  'Location of dest file (default: source_file appended with `_unix`'                  ,                  default                  =                  None                  )                  # Parse the args (argparse automatically grabs the values from                  # sys.argv)                  args                  =                  parser                  .                  parse_args                  ()                  s_file                  =                  args                  .                  source_file                  d_file                  =                  args                  .                  dest_file                  # If the destination file wasn't passed, then assume we want to                  # create a new file based on the old one                  if                  d_file                  is                  None                  :                  file_path                  ,                  file_extension                  =                  bone                  .                  path                  .                  splitext                  (                  s_file                  )                  d_file                  =                  f                  '                  {                  file_path                  }                  _unix                  {                  file_extension                  }                  '                  dos2unix                  (                  s_file                  ,                  d_file                  )                              

Tips and Tricks

Now that you've mastered the nuts of reading and writing files, here are some tips and tricks to help you abound your skills.

__file__

The __file__ attribute is a special attribute of modules, similar to __name__. It is:

"the pathname of the file from which the module was loaded, if it was loaded from a file." (Source

Here's a real globe example. In ane of my past jobs, I did multiple tests for a hardware device. Each test was written using a Python script with the examination script file name used as a title. These scripts would then be executed and could print their status using the __file__ special attribute. Here'south an case folder structure:

                                project/ | ├── tests/ |   ├── test_commanding.py |   ├── test_power.py |   ├── test_wireHousing.py |   └── test_leds.py | └── main.py                              

Running main.py produces the following:

                                >>> python master.py tests/test_commanding.py Started: tests/test_commanding.py Passed! tests/test_power.py Started: tests/test_power.py Passed! tests/test_wireHousing.py Started: tests/test_wireHousing.py Failed! tests/test_leds.py Started: tests/test_leds.py Passed!                              

I was able to run and get the status of all my tests dynamically through use of the __file__ special attribute.

Appending to a File

Sometimes, you may want to suspend to a file or start writing at the cease of an already populated file. This is easily done by using the 'a' character for the mode argument:

                                                  with                  open                  (                  'dog_breeds.txt'                  ,                  'a'                  )                  every bit                  a_writer                  :                  a_writer                  .                  write                  (                  '                  \n                  Beagle'                  )                              

When you examine dog_breeds.txt again, you'll meet that the beginning of the file is unchanged and Beagle is now added to the end of the file:

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    impress                  (                  reader                  .                  read                  ())                  Pug                  Jack Russell Terrier                  English language Springer Spaniel                  German Shepherd                  Staffordshire Bull Terrier                  Condescending King Charles Spaniel                  Golden Retriever                  West Highland White Terrier                  Boxer                  Edge Terrier                  Beagle                              

Working With Two Files at the Same Time

There are times when you may desire to read a file and write to another file at the same fourth dimension. If yous use the example that was shown when you were learning how to write to a file, it can actually be combined into the post-obit:

                                                  d_path                  =                  'dog_breeds.txt'                  d_r_path                  =                  'dog_breeds_reversed.txt'                  with                  open                  (                  d_path                  ,                  'r'                  )                  as                  reader                  ,                  open                  (                  d_r_path                  ,                  'w'                  )                  every bit                  writer                  :                  dog_breeds                  =                  reader                  .                  readlines                  ()                  writer                  .                  writelines                  (                  reversed                  (                  dog_breeds                  ))                              

Creating Your Own Context Manager

There may come a time when you lot'll need finer control of the file object by placing information technology inside a custom class. When you do this, using the with statement tin can no longer be used unless you add a few magic methods: __enter__ and __exit__. By adding these, you'll accept created what's called a context managing director.

__enter__() is invoked when calling the with statement. __exit__() is called upon exiting from the with argument block.

Here'due south a template that you tin use to make your custom class:

                                                  class                  my_file_reader                  ():                  def                  __init__                  (                  self                  ,                  file_path                  ):                  self                  .                  __path                  =                  file_path                  self                  .                  __file_object                  =                  None                  def                  __enter__                  (                  cocky                  ):                  self                  .                  __file_object                  =                  open                  (                  cocky                  .                  __path                  )                  return                  self                  def                  __exit__                  (                  self                  ,                  type                  ,                  val                  ,                  tb                  ):                  self                  .                  __file_object                  .                  close                  ()                  # Additional methods implemented beneath                              

Now that you've got your custom class that is now a context manager, you can utilize it similarly to the open() congenital-in:

                                                  with                  my_file_reader                  (                  'dog_breeds.txt'                  )                  as                  reader                  :                  # Perform custom grade operations                  pass                              

Hither'southward a good instance. Recall the cute Jack Russell image we had? Perhaps you want to open other .png files but don't want to parse the header file each time. Here's an example of how to do this. This example also uses custom iterators. If you're not familiar with them, bank check out Python Iterators:

                                                  class                  PngReader                  ():                  # Every .png file contains this in the header.  Utilize it to verify                  # the file is indeed a .png.                  _expected_magic                  =                  b                  '                  \x89                  PNG                  \r\n\x1a\n                  '                  def                  __init__                  (                  self                  ,                  file_path                  ):                  # Ensure the file has the correct extension                  if                  not                  file_path                  .                  endswith                  (                  '.png'                  ):                  enhance                  NameError                  (                  "File must be a '.png' extension"                  )                  self                  .                  __path                  =                  file_path                  self                  .                  __file_object                  =                  None                  def                  __enter__                  (                  self                  ):                  self                  .                  __file_object                  =                  open                  (                  self                  .                  __path                  ,                  'rb'                  )                  magic                  =                  self                  .                  __file_object                  .                  read                  (                  8                  )                  if                  magic                  !=                  self                  .                  _expected_magic                  :                  raise                  TypeError                  (                  "The File is not a properly formatted .png file!"                  )                  render                  self                  def                  __exit__                  (                  self                  ,                  type                  ,                  val                  ,                  tb                  ):                  self                  .                  __file_object                  .                  shut                  ()                  def                  __iter__                  (                  self                  ):                  # This and __next__() are used to create a custom iterator                  # See https://dbader.org/weblog/python-iterators                  return                  self                  def                  __next__                  (                  cocky                  ):                  # Read the file in "Chunks"                  # See https://en.wikipedia.org/wiki/Portable_Network_Graphics#%22Chunks%22_within_the_file                  initial_data                  =                  cocky                  .                  __file_object                  .                  read                  (                  4                  )                  # The file hasn't been opened or reached EOF.  This means we                  # tin can't get any farther so end the iteration by raising the                  # StopIteration.                  if                  self                  .                  __file_object                  is                  None                  or                  initial_data                  ==                  b                  ''                  :                  raise                  StopIteration                  else                  :                  # Each chunk has a len, type, data (based on len) and crc                  # Grab these values and return them as a tuple                  chunk_len                  =                  int                  .                  from_bytes                  (                  initial_data                  ,                  byteorder                  =                  'big'                  )                  chunk_type                  =                  self                  .                  __file_object                  .                  read                  (                  iv                  )                  chunk_data                  =                  cocky                  .                  __file_object                  .                  read                  (                  chunk_len                  )                  chunk_crc                  =                  self                  .                  __file_object                  .                  read                  (                  4                  )                  return                  chunk_len                  ,                  chunk_type                  ,                  chunk_data                  ,                  chunk_crc                              

You can now open up .png files and properly parse them using your custom context director:

>>>

                                                  >>>                                    with                  PngReader                  (                  'jack_russell.png'                  )                  as                  reader                  :                  >>>                                    for                  l                  ,                  t                  ,                  d                  ,                  c                  in                  reader                  :                  >>>                                    print                  (                  f                  "                  {                  50                  :                  05                  }                  ,                                    {                  t                  }                  ,                                    {                  c                  }                  "                  )                  00013, b'IHDR', b'v\x121k'                  00001, b'sRGB', b'\xae\xce\x1c\xe9'                  00009, b'pHYs', b'(<]\x19'                  00345, b'iTXt', b"L\xc2'Y"                  16384, b'IDAT', b'i\x99\x0c('                  16384, b'IDAT', b'\xb3\xfa\x9a$'                  16384, b'IDAT', b'\xff\xbf\xd1\n'                  16384, b'IDAT', b'\xc3\x9c\xb1}'                  16384, b'IDAT', b'\xe3\x02\xba\x91'                  16384, b'IDAT', b'\xa0\xa99='                  16384, b'IDAT', b'\xf4\x8b.\x92'                  16384, b'IDAT', b'\x17i\xfc\xde'                  16384, b'IDAT', b'\x8fb\x0e\xe4'                  16384, b'IDAT', b')three={'                  01040, b'IDAT', b'\xd6\xb8\xc1\x9f'                  00000, b'IEND', b'\xaeB`\x82'                              

Don't Re-Invent the Snake

There are common situations that you may run into while working with files. Most of these cases can be handled using other modules. Ii mutual file types you may demand to work with are .csv and .json. Existent Python has already put together some great manufactures on how to handle these:

  • Reading and Writing CSV Files in Python
  • Working With JSON Data in Python

Additionally, there are built-in libraries out there that you can use to help you:

  • moving ridge : read and write WAV files (audio)
  • aifc : read and write AIFF and AIFC files (audio)
  • sunau : read and write Dominicus AU files
  • tarfile : read and write tar archive files
  • zipfile : piece of work with Nothing archives
  • configparser : easily create and parse configuration files
  • xml.etree.ElementTree : create or read XML based files
  • msilib : read and write Microsoft Installer files
  • plistlib : generate and parse Mac OS Ten .plist files

There are plenty more out there. Additionally there are even more 3rd political party tools bachelor on PyPI. Some pop ones are the following:

  • PyPDF2 : PDF toolkit
  • xlwings : read and write Excel files
  • Pillow : image reading and manipulation

You lot're a File Sorcerer Harry!

You lot did it! You now know how to work with files with Python, including some avant-garde techniques. Working with files in Python should now be easier than ever and is a rewarding feeling when you first doing it.

In this tutorial you've learned:

  • What a file is
  • How to open up and close files properly
  • How to read and write files
  • Some advanced techniques when working with files
  • Some libraries to piece of work with common file types

If you have whatever questions, hitting u.s.a. up in the comments.

Watch At present This tutorial has a related video course created past the Real Python team. Watch it together with the written tutorial to deepen your understanding: Reading and Writing Files in Python