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

1 of the most common tasks that y'all can do with Python is reading and writing files. Whether it's writing to a simple text file, reading a complicated server log, or even analyzing raw byte information, 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 of import in Python
  • The nuts 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 equally well.

What Is a File?

Before we can get into how to work with files in Python, information technology'southward important to understand what exactly a file is and how modern operating systems handle some of their aspects.

At its core, a file is a contiguous set of bytes used to store data. This data is organized in a specific format and can be anything as simple equally a text file or as complicated as a program executable. In the stop, these byte files are so translated into binary i and 0 for easier processing by the calculator.

Files on well-nigh modern file systems are composed of three main parts:

  1. Header: metadata about the contents of the file (file name, size, type, and and so on)
  2. Data: contents of the file as written by the creator or editor
  3. End of file (EOF): special character that indicates the cease 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 case, a file that has an extension of .gif most likely conforms to the Graphics Interchange Format specification. There are hundreds, if non thousands, of file extensions out there. For this tutorial, y'all'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'due south broken upwardly into three major parts:

  1. Binder Path: the file binder location on the file system where subsequent folders are separated by a forward slash / (Unix) or backslash \ (Windows)
  2. File Name: the actual name of the file
  3. Extension: the cease of the file path pre-pended with a flow (.) used to betoken the file type

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

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

Let's say you lot wanted to access the cats.gif file, and your current location was in the same folder as path. In order to access the file, you demand to go through the path binder and then the to folder, 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 electric current working directory (cwd) is in the to binder of our example folder structure. Instead of referring to the cats.gif past the full path of path/to/cats.gif, the file can exist but referenced by the file name and extension cats.gif.

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

Just what nearly dog_breeds.txt? How would you lot access that without using the full path? Yous tin can use the special characters double-dot (..) to move 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 (..) tin can exist chained together to traverse multiple directories above the current directory. For example, to access animals.csv from the to folder, you would use ../../animals.csv.

Line Endings

1 problem oft encountered when working with file data is the representation of a new line or line ending. The line ending has its roots from back in the Morse Lawmaking era, when a specific pro-sign was used to communicate the stop of a transmission or the finish of a line.

Subsequently, this was standardized for teleprinters by both the International Arrangement for Standardization (ISO) and the American Standards Clan (ASA). ASA standard states that line endings should utilize the sequence of the Carriage Return (CR or \r) and the Line Feed (LF or \n) characters (CR+LF or \r\n). The ISO standard all the same allowed for either the CR+LF characters or merely the LF character.

Windows uses the CR+LF characters to indicate a new line, while Unix and the newer Mac versions utilise only the LF grapheme. This tin can cause some complications when y'all're processing files on an operating organization that is dissimilar than the file's source. Here's a quick example. Let'south say that nosotros examine the file dog_breeds.txt that was created on a Windows system:

                                Pug\r\n Jack Russell Terrier\r\n English language Springer Spaniel\r\north German Shepherd\r\n Staffordshire Balderdash Terrier\r\northward Cavalier Rex Charles Spaniel\r\due north Aureate Retriever\r\n West Highland White Terrier\r\n Boxer\r\n Border Terrier\r\n                              

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

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

This can brand iterating over each line problematic, and yous may demand to business relationship for situations like this.

Grapheme Encodings

Another mutual problem that yous may confront is the encoding of the byte data. An encoding is a translation from byte data to human readable characters. This is typically done by assigning a numerical value to correspond a character. The two most common encodings are the ASCII and UNICODE Formats. ASCII tin only shop 128 characters, while Unicode tin contain up to i,114,112 characters.

ASCII is actually a subset of Unicode (UTF-8), significant that ASCII and Unicode share the aforementioned numerical to character values. It'south important to notation that parsing a file with the incorrect character encoding can atomic number 82 to failures or misrepresentation of the character. For instance, if a file was created using the UTF-8 encoding, and yous endeavor to parse it using the ASCII encoding, if there is a grapheme that is outside of those 128 values, then an fault will be thrown.

Opening and Endmost a File in Python

When you want to work with a file, the first affair to practice is to open it. This is washed by invoking the open() born function. 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 you lot open up a file, the next thing to larn is how to shut it.

Information technology's important to remember that it's your responsibleness to close the file. In about cases, upon termination of an application or script, a file will be airtight eventually. Notwithstanding, in that location is no guarantee when exactly that volition happen. This can lead to unwanted behavior including resource leaks. It's likewise a best practice within Python (Pythonic) to make certain that your code behaves in a manner that is well defined and reduces any unwanted behavior.

When you're manipulating a file, there are two ways that you lot can use to ensure that a file is closed properly, even when encountering an error. The kickoff way to close a file is to use the try-finally cake:

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

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

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

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

The with argument automatically takes care of closing the file once information technology leaves the with block, even in cases of fault. I highly recommend that you lot employ the with argument as much as possible, as it allows for cleaner code and makes handling any unexpected errors easier for you.

Well-nigh likely, you'll also want to use the second positional argument, mode. This statement is a cord that contains multiple characters to represent how you desire to open the file. The default and nearly mutual is 'r', which represents opening the file in read-simply mode as a text file:

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

Other options for modes are fully documented online, but the most commonly used ones are the following:

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

Permit's go back and talk a little about file objects. A file object is:

"an object exposing a file-oriented API (with methods such as read() or write()) to an underlying resource." (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 divers in the io module. Here'due south a quick rundown of how everything lines up.

Text File Types

A text file is the most common file that you'll run across. Hither are some examples of how these files are opened:

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

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

>>>

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

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

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 up                  (                  'abc.txt'                  ,                  'rb'                  )                  open                  (                  'abc.txt'                  ,                  'wb'                  )                              

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

>>>

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

Raw File Types

A raw file type is:

"more often than not used as a low-level building-cake for binary and text streams." (Source)

It is therefore not typically used.

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

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

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

>>>

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

Reading and Writing Opened Files

Once you've opened upwards a file, you'll want to read or write to the file. Beginning off, let's comprehend reading a file. There are multiple methods that tin can be chosen on a file object to help yous 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 -ane is passed, then the entire file is read.
.readline(size=-ane) This reads at nearly size number of characters from the line. This continues to the end of the line and and then wraps dorsum around. If no statement is passed or None or -1 is passed, then the entire line (or residual of the line) is read.
.readlines() This reads the remaining lines from the file object and returns them equally a list.

Using the aforementioned dog_breeds.txt file you used above, let'south go through some examples of how to utilise these methods. Here's an example of how to open up and read the unabridged 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'southward an example 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 & print the first v characters of the line five times                >>>                                print                (                reader                .                readline                (                5                ))                >>>                                # Notice that line is greater than the 5 chars and continues                >>>                                # downwardly the line, reading 5 chars each time until the end of the                >>>                                # line and then "wraps" around                >>>                                print                (                reader                .                readline                (                v                ))                >>>                                impress                (                reader                .                readline                (                5                ))                >>>                                impress                (                reader                .                readline                (                v                ))                >>>                                impress                (                reader                .                readline                (                5                ))                Pug                Jack                Russe                ll Te                rrier                          

Here'south an example of how to read the entire 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\northward', 'German Shepherd\n', 'Staffordshire Bull Terrier\n', 'Condescending King Charles Spaniel\due north', 'Gold Retriever\n', 'West Highland White Terrier\n', 'Boxer\n', 'Edge Terrier\due north']                          

The to a higher place example tin can too exist washed by using list() to create a listing out of the file object:

>>>

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

Iterating Over Each Line in the File

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

>>>

                                                  >>>                                    with                  open                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  as                  reader                  :                  >>>                                    # Read and impress the entire file line past line                  >>>                                    line                  =                  reader                  .                  readline                  ()                  >>>                                    while                  line                  !=                  ''                  :                  # The EOF char is an empty string                  >>>                                    impress                  (                  line                  ,                  end                  =                  ''                  )                  >>>                                    line                  =                  reader                  .                  readline                  ()                  Pug                  Jack Russell Terrier                  English language Springer Spaniel                  German language Shepherd                  Staffordshire Balderdash Terrier                  Cavalier Male monarch Charles Spaniel                  Gold Retriever                  Due west Highland White Terrier                  Boxer                  Border Terrier                              

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

>>>

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

However, 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 unabridged file line by line                  >>>                                    for                  line                  in                  reader                  :                  >>>                                    print                  (                  line                  ,                  end                  =                  ''                  )                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  German language Shepherd                  Staffordshire Bull Terrier                  Cavalier King Charles Spaniel                  Golden Retriever                  West Highland White Terrier                  Boxer                  Edge Terrier                              

This concluding approach is more than Pythonic and can be quicker and more memory 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's up to you to add the appropriate line ending(southward).

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

                                                  with                  open up                  (                  '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'                  )                  every bit                  writer                  :                  # Alternatively you could use                  # writer.writelines(reversed(dog_breeds))                  # Write the dog breeds to the file in reversed club                  for                  breed                  in                  reversed                  (                  dog_breeds                  ):                  writer                  .                  write                  (                  brood                  )                              

Working With Bytes

Sometimes, you may demand to work with files using byte strings. This is done past adding the 'b' graphic symbol to the way argument. All of the same methods for the file object apply. However, each of the methods expect and return a bytes object instead:

>>>

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

Opening a text file using the b flag isn't that interesting. Allow's say we accept this cute motion-picture show 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/3.0)], from Wikimedia Commons

You can actually 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 up similar 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 mode line ending \r\n
0x1A A DOS style EOF character
0x0A A Unix fashion line ending \n

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

>>>

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

A Full Example: dos2unix.py

Let'due south bring this whole affair home and expect at a full example of how to read and write to a file. The following is a dos2unix like tool that volition convert a file that contains line endings of \r\n to \n.

This tool is broken upwards into 3 major sections. The first is str2unix(), which converts a string from \r\north line endings to \north. The 2nd is dos2unix(), which converts a cord that contains \r\due north characters into \n. dos2unix() calls str2unix() internally. Finally, there's the __main__ block, which is called just 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 convert files or strings from dos similar                  line endings with Unix like 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 cord                                      """                  r_str                  =                  input_str                  .                  supplant                  (                  '                  \r\n                  '                  ,                  '                  \n                  '                  )                  render                  r_str                  def                  dos2unix                  (                  source_file                  :                  str                  ,                  dest_file                  :                  str                  ):                  """                                      Converts a file that contains Dos like line endings into Unix similar                                      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 together file existence checking and file overwriting                  # protection                  with                  open                  (                  source_file                  ,                  'r'                  )                  as                  reader                  :                  dos_content                  =                  reader                  .                  read                  ()                  unix_content                  =                  str2unix                  (                  dos_content                  )                  with                  open                  (                  dest_file                  ,                  'w'                  )                  as                  author                  :                  author                  .                  write                  (                  unix_content                  )                  if                  __name__                  ==                  "__main__"                  :                  # Create our Argument parser and prepare its description                  parser                  =                  argparse                  .                  ArgumentParser                  (                  description                  =                  "Script that converts a DOS like file to an Unix like file"                  ,                  )                  # Add the arguments:                  #   - source_file: the source file we want to convert                  #   - dest_file: the destination where the output should go                  # Note: the use 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'                  ,                  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, and then presume we want to                  # create a new file based on the old 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 yous've mastered the basics 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, like 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 existent world instance. In ane 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 proper noun used as a title. These scripts would then be executed and could print their condition using the __file__ special aspect. Here'due south an example folder structure:

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

Running main.py produces the post-obit:

                                >>> 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 employ of the __file__ special attribute.

Appending to a File

Sometimes, you may want to append to a file or start writing at the end of an already populated file. This is easily washed by using the 'a' grapheme for the mode argument:

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

When y'all examine dog_breeds.txt once more, you'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'                  )                  equally                  reader                  :                  >>>                                    print                  (                  reader                  .                  read                  ())                  Pug                  Jack Russell Terrier                  English language Springer Spaniel                  High german Shepherd                  Staffordshire Balderdash Terrier                  Cavalier Male monarch Charles Spaniel                  Golden Retriever                  W Highland White Terrier                  Boxer                  Border Terrier                  Beagle                              

Working With 2 Files at the Aforementioned Time

At that place are times when you may want to read a file and write to some other file at the same time. If y'all utilize the instance that was shown when you were learning how to write to a file, it can really exist combined into the following:

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

Creating Your Own Context Director

There may come up a time when you'll need effectively command of the file object by placing it inside a custom class. When you do this, using the with statement can no longer be used unless yous add together a few magic methods: __enter__ and __exit__. By calculation these, you'll have created what's called 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 tin 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                  (                  cocky                  .                  __path                  )                  render                  self                  def                  __exit__                  (                  self                  ,                  blazon                  ,                  val                  ,                  tb                  ):                  self                  .                  __file_object                  .                  close                  ()                  # Additional methods implemented below                              

Now that you've got your custom class that is now a context manager, you lot tin can apply information technology similarly to the open() congenital-in:

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

Here's a proficient case. Think 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'south an example of how to do this. This example as well uses custom iterators. If yous're not familiar with them, cheque out Python Iterators:

                                                  course                  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\due north\x1a\northward                  '                  def                  __init__                  (                  cocky                  ,                  file_path                  ):                  # Ensure the file has the right extension                  if                  not                  file_path                  .                  endswith                  (                  '.png'                  ):                  raise                  NameError                  (                  "File must be a '.png' extension"                  )                  self                  .                  __path                  =                  file_path                  cocky                  .                  __file_object                  =                  None                  def                  __enter__                  (                  self                  ):                  self                  .                  __file_object                  =                  open                  (                  self                  .                  __path                  ,                  'rb'                  )                  magic                  =                  self                  .                  __file_object                  .                  read                  (                  8                  )                  if                  magic                  !=                  self                  .                  _expected_magic                  :                  enhance                  TypeError                  (                  "The File is not a properly formatted .png file!"                  )                  render                  self                  def                  __exit__                  (                  cocky                  ,                  type                  ,                  val                  ,                  tb                  ):                  self                  .                  __file_object                  .                  close                  ()                  def                  __iter__                  (                  cocky                  ):                  # This and __next__() are used to create a custom iterator                  # Run across https://dbader.org/blog/python-iterators                  return                  cocky                  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                  (                  four                  )                  # The file hasn't been opened or reached EOF.  This means nosotros                  # tin't get any further so end 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                  # Grab these values and return them every bit a tuple                  chunk_len                  =                  int                  .                  from_bytes                  (                  initial_data                  ,                  byteorder                  =                  'big'                  )                  chunk_type                  =                  self                  .                  __file_object                  .                  read                  (                  iv                  )                  chunk_data                  =                  self                  .                  __file_object                  .                  read                  (                  chunk_len                  )                  chunk_crc                  =                  cocky                  .                  __file_object                  .                  read                  (                  four                  )                  return                  chunk_len                  ,                  chunk_type                  ,                  chunk_data                  ,                  chunk_crc                              

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

>>>

                                                  >>>                                    with                  PngReader                  (                  'jack_russell.png'                  )                  as                  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

At that place are common situations that you may encounter while working with files. Most of these cases tin can be handled using other modules. Ii common file types you may need to work with are .csv and .json. Real Python has already put together some swell articles 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 at that place that y'all can use to help yous:

  • moving ridge : read and write WAV files (sound)
  • aifc : read and write AIFF and AIFC files (audio)
  • sunau : read and write Dominicus AU files
  • tarfile : read and write tar archive files
  • zipfile : work with Cypher athenaeum
  • 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

In that location are plenty more out at that place. Additionally there are even more 3rd party tools available on PyPI. Some popular ones are the following:

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

You lot're a File Wizard Harry!

Y'all did it! You now know how to piece of work with files with Python, including some avant-garde techniques. Working with files in Python should at present exist easier than always and is a rewarding feeling when you offset doing information technology.

In this tutorial you lot've learned:

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

If you have whatsoever questions, hit u.s.a. upwardly in the comments.

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