Python gives you three main ways to work with files: the open() function with manual closing, the with statement for automatic cleanup, and built-in methods to read all content at once or line by line
The simplest way to read a file is to open it, read its contents, and close it. Python's open() function takes two arguments: the filename and the mode. The mode tells Python what you want to do — "r" for reading, "w" for writing (which erases the file first), "a" for appending (adding to the end), and "x" for creating a new file that must not already exist.
Once you open a file, you can read it three ways: .read() loads the entire file into memory as one string, .readline() reads one line at a time, and .readlines() returns a list where each item is one line. Writing works similarly — .write() puts a string into the file, and .writelines() writes a list of strings without adding line breaks between them.
The catch with manual open() and close() is that if your code crashes before you close the file, Python leaves it open and locked. The safer approach is the with statement, which closes the file automatically even if something goes wrong. Most Python code uses with because it prevents accidental file leaks.
Key Takeaways
- Use with open(filename, "r") to read files safely — Python closes them automatically when the block ends.
- .read() loads the whole file at once, .readline() gets one line, and .readlines() returns a list of all lines.
- Writing uses "w" mode to replace the file or "a" mode to add to the end without erasing what is there.
- The with statement is safer than calling open() and close() separately because it closes the file even if your code crashes.
- Text mode is the default, but use "rb" or "wb" to read or write binary files like images or PDFs.
Reading an entire file at once
When you want all the content in one go, use .read(). This works well for small files but loads everything into memory, so a 500 MB file will use 500 MB of RAM.
Here is the pattern:
with open("myfile.txt", "r") as file: content = file.read() print(content)
The with statement opens the file, assigns it to the variable file, runs your code, and then closes it automatically. The as keyword gives you a name to use inside the block. Once the block ends (when the indentation stops), the file closes.
If the file does not exist, Python raises a FileNotFoundError. If you want to handle that gracefully, wrap it in a try-except block:
try: with open("myfile.txt", "r") as file: content = file.read() except FileNotFoundError: print("File not found")
Reading a file line by line
For large files, reading one line at a time uses much less memory. Use .readline() to get one line each time you call it, or loop through the file object directly to get each line in turn.
The loop approach is cleaner:
with open("myfile.txt", "r") as file: for line in file: print(line.strip())
Each iteration gives you one line including the newline character at the end. The .strip() method removes that newline and any whitespace before or after the text. Without it, print() adds its own newline, so you get blank lines between each line of the file.
If you need all lines as a list (for example, to sort them or pick specific ones), use .readlines():
with open("myfile.txt", "r") as file: lines = file.readlines() print(lines[0])
This returns a list where lines[0] is the first line, lines[1] is the second, and so on. Each item still includes the newline character, so strip them if you need clean text.
Writing to a file
Use "w" mode to create a new file or replace an existing one completely. Use "a" mode to add text to the end without erasing what is already there.
Writing a single string:
with open("output.txt", "w") as file: file.write("Hello, World!")
This creates output.txt (or overwrites it if it exists) and writes the string. The .write() method does not add a newline, so if you want one, include it in the string:
with open("output.txt", "w") as file: file.write("Line 1\n") file.write("Line 2\n")
To write multiple strings from a list, use .writelines():
lines = ["First line\n", "Second line\n", "Third line\n"] with open("output.txt", "w") as file: file.writelines(lines)
Note that .writelines() does not add newlines between items — you must include \n in each string yourself. To append instead of replacing, change the mode to "a":
with open("output.txt", "a") as file: file.write("New line at the end\n")
Working with different file paths
File paths work differently on Windows and Mac/Linux. Windows uses backslashes (\) and Mac/Linux use forward slashes (/). Python accepts forward slashes on all systems, so use those to keep your code portable.
Instead of open("folder\file.txt"), write open("folder/file.txt"). For paths relative to your script's location, use a dot: open("./data/file.txt") means look in the data folder inside the current folder.
For absolute paths (the full address from the root of your drive), use the full path: open("/Users/yourname/Documents/file.txt") on Mac or open("C:/Users/yourname/Documents/file.txt") on Windows.
If you are working with paths a lot, use the pathlib module, which handles these differences automatically:
from pathlib import Path file_path = Path("data") / "file.txt" with open(file_path, "r") as file: content = file.read()
The / operator joins path parts together correctly for your operating system.
Reading and writing binary files
Text mode (the default) works for .txt, .csv, and .json files. For images, PDFs, or other binary files, use "rb" to read or "wb" to write. The b stands for binary.
Reading a binary file:
with open("image.png", "rb") as file: data = file.read()
This returns bytes instead of a string. You cannot print it directly or search it with text methods. Binary mode is mainly useful when you are copying files, sending them over a network, or passing them to another program that expects raw bytes.
To copy a file without changing it:
with open("original.png", "rb") as source: data = source.read() with open("copy.png", "wb") as destination: destination.write(data)
This preserves the file exactly, including any compression or special formatting.
Handling encoding issues
Text files can be encoded in different ways. Most modern files use UTF-8, which Python assumes by default. If you open a file with a different encoding and do not tell Python, you may see strange characters or get an error.
If you know the encoding, specify it:
with open("file.txt", "r", encoding="latin-1") as file: content = file.read()
Common encodings are utf-8 (the standard), latin-1 (older Windows files), and ascii (plain English text). If you get a UnicodeDecodeError, the file is probably in a different encoding than you assumed.
When writing, you can also specify the encoding:
with open("output.txt", "w", encoding="utf-8") as file: file.write("Text with special characters: café")
UTF-8 handles accents and non-English characters, so it is the safest choice for new files.
Frequently Asked Questions
What is the difference between .read(), .readline(), and .readlines()?
.read() returns the entire file as one string. .readline() returns one line as a string each time you call it. .readlines() returns a list of all lines. Use .read() for small files, loop through the file object for large files, and .readlines() when you need all lines as a list to manipulate them.
Do I have to close the file manually?
No. The with statement closes it automatically when the block ends. If you use open() without with, you must call file.close() yourself, but this is error-prone. Always use with unless you have a specific reason not to.
What happens if I open a file in write mode and it already exists?
Python erases the entire file and starts fresh. If you want to keep the existing content and add to it, use append mode ("a") instead. If you want to make sure the file does not exist before creating it, use "x" mode, which raises an error if the file is already there.
How do I read a file that is in a different folder?
Use a relative or absolute path. A relative path like "data/file.txt" looks in the data folder next to your script. An absolute path like "/Users/yourname/Documents/file.txt" starts from the root of your drive. Use forward slashes on all systems.
What does encoding mean, and why does it matter?
Encoding is how text is stored as bytes in a file. UTF-8 is the modern standard and handles all languages. Older files might use latin-1 or other encodings. If Python cannot read a file, try specifying the encoding: open("file.txt", "r", encoding="latin-1"). UTF-8 is the safest choice for new files.