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

Ane of the most mutual tasks that you can practice with Python is reading and writing files. Whether it'due south writing to a simple text file, reading a complicated server log, or fifty-fifty analyzing raw byte information, all of these situations require reading or writing a file.

In this tutorial, you'll learn:

  • What makes upward a file and why that'southward 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, simply there are some tips in hither that more advanced programmers may appreciate as well.

What Is a File?

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

At its cadre, a file is a face-to-face set of bytes used to store data. This information 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 and then translated into binary 1 and 0 for easier processing past the figurer.

Files on most modern file systems are composed of three main parts:

  1. Header: metadata about the contents of the file (file name, size, blazon, and then on)
  2. Data: contents of the file equally written by the creator or editor
  3. Stop of file (EOF): special graphic symbol 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 example, a file that has an extension of .gif almost likely conforms to the Graphics Interchange Format specification. There are hundreds, if not thousands, of file extensions out in that location. For this tutorial, you lot'll just bargain with .txt or .csv file extensions.

File Paths

When y'all 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. Information technology's broken upwards into three major parts:

  1. Folder 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 bodily name of the file
  3. Extension: the end of the file path pre-pended with a flow (.) used to indicate the file blazon

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

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

Allow's say you wanted to admission the cats.gif file, and your current location was in the same folder as path. In order to access the file, you need to get 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 Proper name is cats. The File Extension is .gif. So the full path is path/to/cats.gif.

Now let's say that your electric current location or electric current working directory (cwd) is in the to folder of our example folder structure. Instead of referring to the cats.gif by the total path of path/to/cats.gif, the file can be merely 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                              

Simply what almost dog_breeds.txt? How would you access that without using the full path? You lot can utilize the special characters double-dot (..) to move one directory up. This means that ../dog_breeds.txt will reference the dog_breeds.txt file from the directory of to:

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

The double-dot (..) can exist chained together to traverse multiple directories above the current directory. For example, to admission animals.csv from the to folder, you would use ../../animals.csv.

Line Endings

One problem ofttimes 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 Code era, when a specific pro-sign was used to communicate the end of a transmission or the end of a line.

Subsequently, 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 apply the sequence of the Wagon Render (CR or \r) and the Line Feed (LF or \n) characters (CR+LF or \r\due north). The ISO standard withal allowed for either the CR+LF characters or just the LF grapheme.

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

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

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

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

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

Graphic symbol Encodings

Some other mutual problem that you lot may face is the encoding of the byte data. An encoding is a translation from byte information to human readable characters. This is typically done past assigning a numerical value to represent a character. The two well-nigh mutual encodings are the ASCII and UNICODE Formats. ASCII tin only store 128 characters, while Unicode tin can incorporate upward to 1,114,112 characters.

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

Opening and Endmost a File in Python

When yous want to piece of work with a file, the first thing to do is to open up it. This is done by invoking the open up() congenital-in function. open() has a unmarried required statement that is the path to the file. open up() has a single return, the file object:

                                            file                =                open                (                'dog_breeds.txt'                )                          

Afterwards you lot open a file, the next thing to learn is how to shut it.

It's important to remember that it's your responsibility to close the file. In most cases, upon termination of an application or script, a file will be closed eventually. Still, there is no guarantee when exactly that will happen. This tin can atomic number 82 to unwanted beliefs including resource leaks. Information technology'due south too a all-time practice within Python (Pythonic) to make certain that your code behaves in a way that is well divers and reduces any unwanted behavior.

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

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

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

The second fashion to close a file is to use the with statement:

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

The with argument automatically takes care of closing the file in one case it leaves the with block, fifty-fifty in cases of fault. I highly recommend that you apply the with argument as much equally possible, as it allows for cleaner code and makes handling any unexpected errors easier for you.

Almost likely, you lot'll also want to utilise the second positional argument, mode. This argument is a string that contains multiple characters to represent how yous desire to open up the file. The default and most common is 'r', which represents opening the file in read-only mode every bit a text file:

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

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

Character Meaning
'r' Open for reading (default)
'due west' Open up for writing, truncating (overwriting) the file beginning
'rb' or 'wb' Open in binary fashion (read/write using byte data)

Allow'southward 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 resources." (Source)

There 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. Here's a quick rundown of how everything lines up.

Text File Types

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

>>>

                                                  >>>                                    file                  =                  open                  (                  'dog_breeds.txt'                  )                  >>>                                    type                  (                  file                  )                  <class '_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                  )                  <class '_io.BufferedReader'>                  >>>                                    file                  =                  open                  (                  'dog_breeds.txt'                  ,                  'wb'                  )                  >>>                                    type                  (                  file                  )                  <class '_io.BufferedWriter'>                              

Raw File Types

A raw file type is:

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

It is therefore not typically used.

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

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

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

>>>

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

Reading and Writing Opened Files

Once you've opened upwardly a file, yous'll want to read or write to the file. First off, allow'southward embrace reading a file. There are multiple methods that can be called on a file object to aid you out:

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

Using the same dog_breeds.txt file you lot used above, let'southward go through some examples of how to utilize these methods. Here'south an example of how to open up and read the entire file using .read():

>>>

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

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

>>>

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

Here'southward 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\north', 'English language Springer Spaniel\n', 'German Shepherd\north', 'Staffordshire Bull Terrier\due north', 'Condescending King Charles Spaniel\due north', 'Golden Retriever\n', 'Westward Highland White Terrier\n', 'Boxer\northward', 'Border Terrier\n']                          

The above instance can also exist done by using listing() to create a listing out of the file object:

>>>

                                            >>>                                f                =                open                (                'dog_breeds.txt'                )                >>>                                listing                (                f                )                ['Pug\due north', 'Jack Russell Terrier\due north', 'English language Springer Spaniel\north', 'German Shepherd\due north', 'Staffordshire Bull Terrier\n', 'Condescending King Charles Spaniel\n', 'Golden Retriever\due north', 'West Highland White Terrier\n', 'Boxer\due north', 'Border Terrier\n']                          

Iterating Over Each Line in the File

A mutual affair to practice while reading a file is to iterate over each line. Here'southward 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 Male monarch Charles Spaniel                  Gilt Retriever                  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. Remember, .readlines() returns a list where each element in the listing represents a line in the file:

>>>

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

Notwithstanding, the to a higher place examples tin be further simplified by iterating over the file object itself:

>>>

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

This final approach is more than Pythonic and tin can be quicker and more retentiveness efficient. Therefore, it is suggested you lot utilize this instead.

Now let'southward 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 cord 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(south).

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

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

Working With Bytes

Sometimes, y'all may need to work with files using byte strings. This is done past adding the 'b' graphic symbol to the style argument. All of the same methods for the file object utilise. Even so, each of the methods look and return a bytes object instead:

>>>

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

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 BY 3.0 (https://creativecommons.org/licenses/by/3.0)], from Wikimedia Commons

Y'all tin actually open that file in Python and examine the contents! Since the .png file format is well defined, the header of the file is viii bytes broken up like this:

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

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

>>>

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

A Full Case: dos2unix.py

Let's bring this whole thing dwelling and look at a total instance 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 cleaved up into three major sections. The first is str2unix(), which converts a string from \r\northward line endings to \n. The 2nd is dos2unix(), which converts a string that contains \r\n characters into \north. dos2unix() calls str2unix() internally. Finally, in that location's the __main__ block, which is called merely when the file is executed every bit a script. Think of it as the main function found in other programming languages.

                                                  """                  A uncomplicated script and library to catechumen files or strings from dos like                  line endings with Unix similar line endings.                  """                  import                  argparse                  import                  os                  def                  str2unix                  (                  input_str                  :                  str                  )                  ->                  str                  :                  r                  """                                      Converts the string from \r\n line endings to \n                                      Parameters                                      ----------                                      input_str                                      The string whose line endings will be converted                                      Returns                                      -------                                      The converted cord                                      """                  r_str                  =                  input_str                  .                  replace                  (                  '                  \r\n                  '                  ,                  '                  \north                  '                  )                  return                  r_str                  def                  dos2unix                  (                  source_file                  :                  str                  ,                  dest_file                  :                  str                  ):                  """                                      Converts a file that contains Dos like line endings into Unix like                                      Parameters                                      ----------                                      source_file                                      The path to the source file to exist converted                                      dest_file                                      The path to the converted file for output                                      """                  # NOTE: Could add file beingness checking and file overwriting                  # protection                  with                  open                  (                  source_file                  ,                  'r'                  )                  as                  reader                  :                  dos_content                  =                  reader                  .                  read                  ()                  unix_content                  =                  str2unix                  (                  dos_content                  )                  with                  open up                  (                  dest_file                  ,                  'westward'                  )                  as                  writer                  :                  writer                  .                  write                  (                  unix_content                  )                  if                  __name__                  ==                  "__main__"                  :                  # Create our Argument parser and gear up 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 nosotros want to convert                  #   - dest_file: the destination where the output should get                  # Note: the use of the argument blazon 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, 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

At present that you've mastered the basics of reading and writing files, hither are some tips and tricks to help you grow your skills.

__file__

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

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

Here's a real globe instance. 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 exist executed and could impress their status using the __file__ special attribute. Hither's an instance folder construction:

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

Running primary.py produces the post-obit:

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

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

Appending to a File

Sometimes, yous may want to append to a file or start writing at the stop of an already populated file. This is easily done past using the 'a' character for the mode argument:

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

When you examine dog_breeds.txt again, you'll see that the kickoff of the file is unchanged and Beagle is now added to the finish of the file:

>>>

                                                  >>>                                    with                  open up                  (                  'dog_breeds.txt'                  ,                  'r'                  )                  equally                  reader                  :                  >>>                                    print                  (                  reader                  .                  read                  ())                  Pug                  Jack Russell Terrier                  English Springer Spaniel                  German Shepherd                  Staffordshire Balderdash Terrier                  Cavalier King Charles Spaniel                  Golden Retriever                  Westward 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 aforementioned time. If you use the example that was shown when you lot 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'                  )                  every bit                  reader                  ,                  open up                  (                  d_r_path                  ,                  'w'                  )                  as                  writer                  :                  dog_breeds                  =                  reader                  .                  readlines                  ()                  writer                  .                  writelines                  (                  reversed                  (                  dog_breeds                  ))                              

Creating Your Own Context Manager

There may come a time when y'all'll need effectively control of the file object by placing it inside a custom course. When you practice this, using the with argument can no longer be used unless you lot add a few magic methods: __enter__ and __exit__. By adding these, yous'll have created what's called a context manager.

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

Here'southward a template that you lot can use to brand your custom class:

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

Now that you've got your custom grade that is now a context managing director, you can use it similarly to the open() built-in:

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

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

                                                  class                  PngReader                  ():                  # Every .png file contains this in the header.  Apply information technology to verify                  # the file is indeed a .png.                  _expected_magic                  =                  b                  '                  \x89                  PNG                  \r\n\x1a\n                  '                  def                  __init__                  (                  self                  ,                  file_path                  ):                  # Ensure the file has the correct extension                  if                  not                  file_path                  .                  endswith                  (                  '.png'                  ):                  raise                  NameError                  (                  "File must be a '.png' extension"                  )                  self                  .                  __path                  =                  file_path                  self                  .                  __file_object                  =                  None                  def                  __enter__                  (                  self                  ):                  self                  .                  __file_object                  =                  open                  (                  self                  .                  __path                  ,                  'rb'                  )                  magic                  =                  cocky                  .                  __file_object                  .                  read                  (                  8                  )                  if                  magic                  !=                  self                  .                  _expected_magic                  :                  raise                  TypeError                  (                  "The File is not a properly formatted .png file!"                  )                  return                  self                  def                  __exit__                  (                  self                  ,                  type                  ,                  val                  ,                  tb                  ):                  self                  .                  __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 we                  # can't become any further so terminate the iteration by raising the                  # StopIteration.                  if                  self                  .                  __file_object                  is                  None                  or                  initial_data                  ==                  b                  ''                  :                  raise                  StopIteration                  else                  :                  # Each clamper has a len, blazon, data (based on len) and crc                  # Grab these values and return them as a tuple                  chunk_len                  =                  int                  .                  from_bytes                  (                  initial_data                  ,                  byteorder                  =                  'big'                  )                  chunk_type                  =                  self                  .                  __file_object                  .                  read                  (                  4                  )                  chunk_data                  =                  cocky                  .                  __file_object                  .                  read                  (                  chunk_len                  )                  chunk_crc                  =                  self                  .                  __file_object                  .                  read                  (                  4                  )                  return                  chunk_len                  ,                  chunk_type                  ,                  chunk_data                  ,                  chunk_crc                              

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

>>>

                                                  >>>                                    with                  PngReader                  (                  'jack_russell.png'                  )                  every bit                  reader                  :                  >>>                                    for                  fifty                  ,                  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\due north'                  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')3={'                  01040, b'IDAT', b'\xd6\xb8\xc1\x9f'                  00000, b'IEND', b'\xaeB`\x82'                              

Don't Re-Invent the Snake

In that location are common situations that you may run into while working with files. Well-nigh of these cases can be handled using other modules. Two common file types you may demand to work with are .csv and .json. Real Python has already put together some great articles on how to handle these:

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

Additionally, at that place are born libraries out in that location that you can utilise to assist you:

  • wave : read and write WAV files (audio)
  • aifc : read and write AIFF and AIFC files (sound)
  • sunau : read and write Sun AU files
  • tarfile : read and write tar annal files
  • zipfile : 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

There are enough more out there. Additionally there are even more than 3rd party tools bachelor on PyPI. Some pop ones are the post-obit:

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

You're a File Wizard Harry!

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

In this tutorial y'all've learned:

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

If y'all have whatever questions, striking us upward in the comments.

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