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

One of the almost common tasks that you can do with Python is reading and writing files. Whether it'southward writing to a simple text file, reading a complicated server log, or even analyzing raw byte data, all of these situations crave reading or writing a file.

In this tutorial, you'll learn:

  • What makes up a file and why that's of import in Python
  • The basics of reading and writing files in Python
  • Some basic 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 capeesh as well.

What Is a File?

Before we can go into how to work with files in Python, it's important to understand what exactly a file is and how modernistic operating systems handle some of their aspects.

At its core, a file is a contiguous set up of bytes used to shop data. This information is organized in a specific format and can exist anything as simple every bit a text file or as complicated every bit a plan executable. In the end, these byte files are and so translated into binary 1 and 0 for easier processing by the estimator.

Files on most modern file systems are equanimous of three master parts:

  1. Header: metadata about the contents of the file (file name, size, type, and then on)
  2. Data: contents of the file as written by the creator or editor
  3. Stop of file (EOF): special grapheme that indicates the end 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 by an extension. For example, a file that has an extension of .gif nearly likely conforms to the Graphics Interchange Format specification. There are hundreds, if not thousands, of file extensions out there. For this tutorial, you'll but deal with .txt or .csv file extensions.

File Paths

When you access a file on an operating organization, a file path is required. The file path is a string that represents the location of a file. It's broken up into three major parts:

  1. Folder Path: the file binder location on the file organization where subsequent folders are separated past a forward slash / (Unix) or backslash \ (Windows)
  2. File Name: the actual name of the file
  3. Extension: the end of the file path pre-pended with a period (.) used to indicate the file type

Here'due south a quick example. Let'south say y'all have a file located within a file construction like this:

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

Let's say you wanted to access the cats.gif file, and your current location was in the aforementioned folder as path. In society to access the file, you need to go through the path folder and 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'due south say that your electric current location or current working directory (cwd) is in the to folder of our instance folder structure. Instead of referring to the cats.gif by the full path of path/to/cats.gif, the file can be simply referenced by the file proper name and extension cats.gif.

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

Merely what well-nigh dog_breeds.txt? How would you access that without using the full path? You tin can utilise the special characters double-dot (..) to motion one directory up. This ways 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 in a higher place the current directory. For example, to admission animals.csv from the to folder, you would employ ../../animals.csv.

Line Endings

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

Later, this was standardized for teleprinters by both the International Organization for Standardization (ISO) and the American Standards Association (ASA). ASA standard states that line endings should use the sequence of the Railroad vehicle Return (CR or \r) and the Line Feed (LF or \n) characters (CR+LF or \r\n). The ISO standard however allowed for either the CR+LF characters or only the LF character.

Windows uses the CR+LF characters to point a new line, while Unix and the newer Mac versions utilize just the LF character. This tin crusade some complications when you're processing files on an operating system that is different than the file's source. Here's a quick example. Permit'southward 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\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\northward                              

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

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

This tin make iterating over each line problematic, and y'all 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 being readable characters. This is typically done past assigning a numerical value to represent a graphic symbol. The 2 most common encodings are the ASCII and UNICODE Formats. ASCII tin can simply store 128 characters, while Unicode tin contain up to 1,114,112 characters.

ASCII is actually a subset of Unicode (UTF-viii), meaning that ASCII and Unicode share the same numerical to character values. Information technology's important to notation that parsing a file with the wrong character encoding tin lead to failures or misrepresentation of the character. For example, if a file was created using the UTF-8 encoding, and you try to parse it using the ASCII encoding, if in that location is a graphic symbol that is outside of those 128 values, then an error will be thrown.

Opening and Closing a File in Python

When you lot desire to piece of work with a file, the outset thing to practice is to open it. This is done by invoking the open() built-in office. open() has a single required argument that is the path to the file. open() has a single return, the file object:

                                            file                =                open                (                'dog_breeds.txt'                )                          

After yous open a file, the next thing to learn is how to shut it.

It's important to call up that information technology'southward your responsibility to shut the file. In virtually cases, upon termination of an application or script, a file will exist closed somewhen. Withal, in that location is no guarantee when exactly that will happen. This tin atomic number 82 to unwanted behavior including resource leaks. Information technology's also a best practice within Python (Pythonic) to make sure that your lawmaking behaves in a mode that is well defined and reduces any unwanted beliefs.

When you're manipulating a file, in that location are two ways that you can use to ensure that a file is closed properly, fifty-fifty when encountering an mistake. The first fashion to close a file is to use the try-finally block:

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

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

The second way to close a file is to use the with argument:

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

The with statement automatically takes care of endmost the file once information technology leaves the with cake, even in cases of fault. I highly recommend that yous employ the with statement every bit much as possible, as information technology allows for cleaner code and makes handling any unexpected errors easier for you.

Most probable, you'll besides want to utilize the second positional argument, 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 style equally a text file:

                                            with                open                (                'dog_breeds.txt'                ,                'r'                )                every bit                reader                :                # Further file processing goes here                          

Other options for modes are fully documented online, but the most usually used ones are the post-obit:

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

Let'southward go back and talk a little about file objects. A file object is:

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

In that location are three different categories of file objects:

  • Text files
  • Buffered binary files
  • Raw binary files

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

Text File Types

A text file is the most common file that you lot'll see. 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() will render a TextIOWrapper file object:

>>>

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

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

Buffered Binary File Types

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

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

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

>>>

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

Raw File Types

A raw file blazon is:

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

Information technology is therefore not typically used.

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

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

With these types of files, open up() volition return a FileIO file object:

>>>

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

Reading and Writing Opened Files

Once y'all've opened up a file, you'll want to read or write to the file. First off, let's cover reading a file. There are multiple methods that tin can be called on a file object to assist you out:

Method What It Does
.read(size=-1) This reads from the file based on the number of size bytes. If no argument is passed or None or -1 is passed, then the entire file is read.
.readline(size=-i) This reads at nearly size number of characters from the line. This continues to the end of the line and then wraps back around. If no argument is passed or None or -1 is passed, then the unabridged line (or rest of the line) is read.
.readlines() This reads the remaining lines from the file object and returns them every bit a list.

Using the aforementioned dog_breeds.txt file you used above, let's go through some examples of how to use these methods. Hither's an case of how to open and read the entire file using .read():

>>>

                                            >>>                                with                open                (                'dog_breeds.txt'                ,                'r'                )                every bit                reader                :                >>>                                # Read & impress the entire file                >>>                                print                (                reader                .                read                ())                Pug                Jack Russell Terrier                English language Springer Spaniel                German Shepherd                Staffordshire Balderdash Terrier                Cavalier Male monarch Charles Spaniel                Golden Retriever                Due west Highland White Terrier                Boxer                Border Terrier                          

Here's an example of how to read five bytes of a line each fourth dimension using the Python .readline() method:

>>>

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

Here'southward an example of how to read the entire file equally 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\north', 'Staffordshire Bull Terrier\n', 'Cavalier King Charles Spaniel\n', 'Gilded Retriever\north', 'West Highland White Terrier\n', 'Boxer\n', 'Edge Terrier\n']                          

The to a higher place example can also be done by using list() to create a listing out of the file object:

>>>

                                            >>>                                f                =                open                (                'dog_breeds.txt'                )                >>>                                listing                (                f                )                ['Pug\n', 'Jack Russell Terrier\n', 'English Springer Spaniel\north', 'German language Shepherd\northward', 'Staffordshire Bull Terrier\n', 'Cavalier King Charles Spaniel\n', 'Golden Retriever\due north', 'West Highland White Terrier\n', 'Boxer\north', '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. Here's an example of how to use the Python .readline() method to perform that iteration:

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    # Read and print the entire file line past line                  >>>                                    line                  =                  reader                  .                  readline                  ()                  >>>                                    while                  line                  !=                  ''                  :                  # The EOF char is an empty string                  >>>                                    print                  (                  line                  ,                  cease                  =                  ''                  )                  >>>                                    line                  =                  reader                  .                  readline                  ()                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  High german Shepherd                  Staffordshire Bull Terrier                  Cavalier King Charles Spaniel                  Aureate Retriever                  Due west Highland White Terrier                  Boxer                  Edge Terrier                              

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

>>>

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

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

>>>

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

This concluding approach is more Pythonic and tin be quicker and more retentivity efficient. Therefore, it is suggested you use this instead.

Now allow's dive into writing files. Equally 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's upwardly to you to add the appropriate line ending(s).

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

                                                  with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  # Note: readlines doesn't trim the line endings                  dog_breeds                  =                  reader                  .                  readlines                  ()                  with                  open                  (                  'dog_breeds_reversed.txt'                  ,                  'w'                  )                  as                  author                  :                  # Alternatively you could apply                  # writer.writelines(reversed(dog_breeds))                  # Write the dog breeds to the file in reversed order                  for                  breed                  in                  reversed                  (                  dog_breeds                  ):                  writer                  .                  write                  (                  breed                  )                              

Working With Bytes

Sometimes, you may demand to work with files using byte strings. This is done past calculation the 'b' grapheme to the mode statement. All of the same methods for the file object apply. However, each of the methods expect and render a bytes object instead:

>>>

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

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

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

You can actually open that file in Python and examine the contents! Since the .png file format is well divers, the header of the file is 8 bytes broken up similar this:

Value Interpretation
0x89 A "magic" number to indicate that this is the first of a PNG
0x50 0x4E 0x47 PNG in ASCII
0x0D 0x0A A DOS style line ending \r\n
0x1A A DOS style EOF character
0x0A A Unix mode line ending \northward

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

>>>

                                                  >>>                                    with                  open up                  (                  'jack_russell.png'                  ,                  'rb'                  )                  equally                  byte_reader                  :                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  one                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  3                  ))                  >>>                                    print                  (                  byte_reader                  .                  read                  (                  2                  ))                  >>>                                    impress                  (                  byte_reader                  .                  read                  (                  1                  ))                  >>>                                    impress                  (                  byte_reader                  .                  read                  (                  1                  ))                  b'\x89'                  b'PNG'                  b'\r\north'                  b'\x1a'                  b'\n'                              

A Full Example: dos2unix.py

Let's bring this whole affair home and wait at a full instance of how to read and write to a file. The following is a dos2unix similar tool that volition catechumen a file that contains line endings of \r\n to \north.

This tool is broken up into three major sections. The first is str2unix(), which converts a cord from \r\n line endings to \n. The 2nd is dos2unix(), which converts a cord that contains \r\n characters into \north. dos2unix() calls str2unix() internally. Finally, there'due south the __main__ block, which is chosen only when the file is executed as a script. Think of it equally the main function found in other programming languages.

                                                  """                  A simple script and library to convert files or strings from dos like                  line endings with Unix like line endings.                  """                  import                  argparse                  import                  os                  def                  str2unix                  (                  input_str                  :                  str                  )                  ->                  str                  :                  r                  """                                      Converts the cord from \r\n line endings to \n                                      Parameters                                      ----------                                      input_str                                      The string whose line endings will exist converted                                      Returns                                      -------                                      The converted cord                                      """                  r_str                  =                  input_str                  .                  supplant                  (                  '                  \r\northward                  '                  ,                  '                  \n                  '                  )                  return                  r_str                  def                  dos2unix                  (                  source_file                  :                  str                  ,                  dest_file                  :                  str                  ):                  """                                      Converts a file that contains Dos like 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                                      """                  # Annotation: Could add file existence checking and file overwriting                  # protection                  with                  open                  (                  source_file                  ,                  'r'                  )                  equally                  reader                  :                  dos_content                  =                  reader                  .                  read                  ()                  unix_content                  =                  str2unix                  (                  dos_content                  )                  with                  open                  (                  dest_file                  ,                  'due west'                  )                  every bit                  writer                  :                  writer                  .                  write                  (                  unix_content                  )                  if                  __name__                  ==                  "__main__"                  :                  # Create our Argument parser and prepare its description                  parser                  =                  argparse                  .                  ArgumentParser                  (                  clarification                  =                  "Script that converts a DOS similar file to an Unix like file"                  ,                  )                  # Add the arguments:                  #   - source_file: the source file we desire to catechumen                  #   - dest_file: the destination where the output should get                  # Note: the use of the argument type of argparse.FileType could                  # streamline some things                  parser                  .                  add_argument                  (                  'source_file'                  ,                  assist                  =                  'The location of the source '                  )                  parser                  .                  add_argument                  (                  '--dest_file'                  ,                  help                  =                  '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 one-time one                  if                  d_file                  is                  None                  :                  file_path                  ,                  file_extension                  =                  os                  .                  path                  .                  splitext                  (                  s_file                  )                  d_file                  =                  f                  '                  {                  file_path                  }                  _unix                  {                  file_extension                  }                  '                  dos2unix                  (                  s_file                  ,                  d_file                  )                              

Tips and Tricks

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

__file__

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

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

Here's a real world example. In one of my past jobs, I did multiple tests for a hardware device. Each test was written using a Python script with the test script file name used as a title. These scripts would then be executed and could print their status using the __file__ special attribute. Here's an instance 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 main.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, y'all may want to suspend to a file or outset writing at the terminate of an already populated file. This is easily done by using the 'a' character for the mode argument:

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

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

>>>

                                                  >>>                                    with                  open up                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    print                  (                  reader                  .                  read                  ())                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  German Shepherd                  Staffordshire Balderdash Terrier                  Cavalier King Charles Spaniel                  Gilt Retriever                  West Highland White Terrier                  Boxer                  Edge Terrier                  Beagle                              

Working With Two Files at the Same Time

There are times when you may want to read a file and write to another file at the same time. If yous use the instance that was shown when you were learning how to write to a file, it can actually be combined into the following:

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

Creating Your Own Context Managing director

There may come up a time when you'll demand effectively control of the file object past placing it within a custom class. When y'all do this, using the with statement tin no longer be used unless you add a few magic methods: __enter__ and __exit__. By calculation these, you'll accept created what'southward chosen a context manager.

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

Here's a template that y'all can use to make your custom class:

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

Now that y'all've got your custom class that is at present a context manager, yous tin can use it similarly to the open() built-in:

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

Here's a practiced example. Remember the beautiful 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 practice this. This example also uses custom iterators. If you're not familiar with them, check out Python Iterators:

                                                  class                  PngReader                  ():                  # Every .png file contains this in the header.  Use it to verify                  # the file is indeed a .png.                  _expected_magic                  =                  b                  '                  \x89                  PNG                  \r\northward\x1a\due north                  '                  def                  __init__                  (                  self                  ,                  file_path                  ):                  # Ensure the file has the right extension                  if                  non                  file_path                  .                  endswith                  (                  '.png'                  ):                  raise                  NameError                  (                  "File must be a '.png' extension"                  )                  self                  .                  __path                  =                  file_path                  self                  .                  __file_object                  =                  None                  def                  __enter__                  (                  self                  ):                  cocky                  .                  __file_object                  =                  open                  (                  self                  .                  __path                  ,                  'rb'                  )                  magic                  =                  self                  .                  __file_object                  .                  read                  (                  8                  )                  if                  magic                  !=                  self                  .                  _expected_magic                  :                  raise                  TypeError                  (                  "The File is non a properly formatted .png file!"                  )                  return                  self                  def                  __exit__                  (                  self                  ,                  type                  ,                  val                  ,                  tb                  ):                  cocky                  .                  __file_object                  .                  close                  ()                  def                  __iter__                  (                  self                  ):                  # This and __next__() are used to create a custom iterator                  # See https://dbader.org/blog/python-iterators                  return                  self                  def                  __next__                  (                  self                  ):                  # Read the file in "Chunks"                  # See https://en.wikipedia.org/wiki/Portable_Network_Graphics#%22Chunks%22_within_the_file                  initial_data                  =                  self                  .                  __file_object                  .                  read                  (                  4                  )                  # The file hasn't been opened or reached EOF.  This means nosotros                  # can't become whatever further and then cease the iteration by raising the                  # StopIteration.                  if                  self                  .                  __file_object                  is                  None                  or                  initial_data                  ==                  b                  ''                  :                  raise                  StopIteration                  else                  :                  # Each clamper has a len, type, data (based on len) and crc                  # Catch these values and return them equally a tuple                  chunk_len                  =                  int                  .                  from_bytes                  (                  initial_data                  ,                  byteorder                  =                  'big'                  )                  chunk_type                  =                  self                  .                  __file_object                  .                  read                  (                  4                  )                  chunk_data                  =                  cocky                  .                  __file_object                  .                  read                  (                  chunk_len                  )                  chunk_crc                  =                  self                  .                  __file_object                  .                  read                  (                  iv                  )                  return                  chunk_len                  ,                  chunk_type                  ,                  chunk_data                  ,                  chunk_crc                              

You tin now open .png files and properly parse them using your custom context manager:

>>>

                                                  >>>                                    with                  PngReader                  (                  'jack_russell.png'                  )                  every bit                  reader                  :                  >>>                                    for                  l                  ,                  t                  ,                  d                  ,                  c                  in                  reader                  :                  >>>                                    print                  (                  f                  "                  {                  l                  :                  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')iii={'                  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 meet while working with files. Most of these cases can be handled using other modules. Two common file types you may need to work with are .csv and .json. Real Python has already put together some bang-up articles on how to handle these:

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

Additionally, there are congenital-in libraries out there that you can use to assist you:

  • wave : read and write WAV files (audio)
  • aifc : read and write AIFF and AIFC files (sound)
  • sunau : read and write Lord's day AU files
  • tarfile : read and write tar archive files
  • zipfile : piece of work with ZIP 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 X .plist files

At that place are plenty more than out there. Additionally there are even more than 3rd party tools available on PyPI. Some popular ones are the post-obit:

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

You're a File Wizard Harry!

You lot did it! Y'all now know how to work with files with Python, including some advanced techniques. Working with files in Python should now be easier than ever and is a rewarding feeling when you start doing it.

In this tutorial y'all've learned:

  • What a file is
  • How to open and close files properly
  • How to read and write files
  • Some avant-garde techniques when working with files
  • Some libraries to work with common file types

If you have any questions, striking us up in the comments.

Scout Now This tutorial has a related video form created by the Real Python team. Watch information technology together with the written tutorial to deepen your understanding: Reading and Writing Files in Python