Recommended Free Tools
To save a Python list or dictionary to a file, open the file in text mode with encoding="utf-8" and pass it to json.dump(). To load it later, open the file and pass it to json.load(). Each file should hold one JSON document. If you have many records, put them in one list or store them in JSON Lines format. Calling json.dump() repeatedly on the same file does not produce a valid file.
The basic write and read workflow
The standard library’s json module needs no installation. The following script writes a dictionary to a file and reads it back:
As an Amazon Associate I earn from qualifying purchases.
import json
record = {"name": "Ada", "active": True}
with open("record.json", "w", encoding="utf-8") as f:
json.dump(record, f, ensure_ascii=False, indent=2)
with open("record.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["name"]) # Ada
Three parts of this pattern matter. The with block closes the file even if an error occurs. The encoding argument is set explicitly rather than left to the platform default. The indent=2 option makes the saved file readable by people, at the cost of a few extra bytes of whitespace. Compact output is the default when indent is omitted.
dump, dumps, load, and loads
The module has two families of functions. The ones ending in s work with strings, and the others work with file objects. Use the file versions when the data lives in a file.
#1 Best Overall
| Function | Input | Output | Typical use |
|---|---|---|---|
json.dump(obj, fp) |
Python value and a writable file object | Writes JSON text to fp |
Saving to a file |
json.dumps(obj) |
Python value | Returns a str |
Sending JSON in a request or logging it |
json.load(fp) |
Readable file object | Python value parsed from the whole document | Reading a file |
json.loads(s) |
str, bytes, or bytearray |
Python value | Parsing JSON already in memory |
Because json.dump() writes str values, the file must accept text. A file opened with "wb" raises TypeError. Open it with "w" and an encoding instead.
Encoding: why UTF-8 and what ensure_ascii changes
The Python tutorial’s “Input and Output” section states: “JSON files must be encoded in UTF-8.” It recommends passing encoding="utf-8" whenever you open a JSON text file. Skipping this argument can cause a file to be written in one encoding and read in another, and the mismatch often shows up only with non-English text.
The ensure_ascii option controls how non-ASCII characters appear in the output:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute| Setting | Input value | Text written to the file | Notes |
|---|---|---|---|
ensure_ascii=True (default) |
"Zoë" |
"Zoë" |
Output is pure ASCII and safe in any encoding, but harder to read |
ensure_ascii=False |
"Zoë" |
"Zoë" |
Characters are written directly, so the file must be saved as UTF-8 |
The default escaping is a reasonable choice when you control neither the reader nor the encoding. When you open the file with encoding="utf-8", ensure_ascii=False gives human-readable output without any loss.
Rank #2
Why repeated dump() calls produce invalid JSON
This is the most common mistake with JSON files. The json module reference puts it directly: “Unlike pickle and marshal, JSON is not a framed protocol, so trying to serialize multiple objects with repeated calls to dump() using the same fp will result in an invalid JSON file.”
import json
with open("bad.json", "w", encoding="utf-8") as f:
json.dump({"name": "Ada"}, f)
json.dump({"name": "Grace"}, f)
with open("bad.json", "r", encoding="utf-8") as f:
json.load(f) # raises json.JSONDecodeError: Extra data
The file contains {"name": "Ada"}{"name": "Grace"}. Each call writes a complete document, but nothing marks where one ends and the next begins. json.load() reads one document and then finds unexpected trailing content.
Storing many records in a file
There are two reliable ways to store several records. Choose based on whether the records are read as a single unit or processed one at a time.
Option 1: one list in one document
If the records belong together, put them in a list and call json.dump() once:
import json
records = [{"id": 1, "name": "Ada"}, {"id": 2, "name": "Grace"}]
with open("records.json", "w", encoding="utf-8") as f:
json.dump(records, f, ensure_ascii=False, indent=2)
with open("records.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
The whole file is loaded into memory at once, which is fine for files of moderate size.
Option 2: JSON Lines, one object per line
For logs, exports, or large collections that you process one record at a time, write one JSON object per line. Each line is a separate document, so you can read the file line by line without loading all of it:
import json
records = [{"id": 1, "name": "Ada"}, {"id": 2, "name": "Grace"}]
with open("records.jsonl", "w", encoding="utf-8") as f:
for record in records:
f.write(json.dumps(record) + "n")
with open("records.jsonl", "r", encoding="utf-8") as f:
loaded = [json.loads(line) for line in f if line.strip()]
This works because json.dumps() without indent emits no line breaks inside a record. Do not use indent with this format, because each record must fit on one line.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Validate and format from the command line
The json module provides a command-line tool for checking and reformatting JSON. The current reference documents python -m json, and python -m json.tool remains supported for backward compatibility. It can read from standard input, write to standard output, accept input and output file names, sort keys, and control indentation.
# Validate and pretty-print to the terminal
python -m json record.json
# Pretty-print with sorted keys and four-space indentation into a new file
python -m json.tool --sort-keys --indent 4 record.json formatted.json
# Read from standard input
cat record.json | python -m json
# Check each line of a JSON Lines file
python -m json --json-lines records.jsonl
When the input is invalid, the tool reports an error instead of printing formatted output. Use it to find the line that breaks a file before you debug your Python code.
Handling errors when loading JSON
Invalid JSON raises json.JSONDecodeError, a subclass of ValueError. The exception provides msg, lineno, and colno attributes, which are useful for showing where the problem is:
import json
try:
with open("record.json", "r", encoding="utf-8") as f:
data = json.load(f)
except json.JSONDecodeError as exc:
print(f"Invalid JSON at line {exc.lineno}, column {exc.colno}: {exc.msg}")
Catch JSONDecodeError specifically. Catching every exception, or every ValueError, hides other problems. A missing file raises FileNotFoundError, and a file that is not valid UTF-8 raises UnicodeDecodeError before any JSON parsing begins.
Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
JSONDecodeError: Extra data |
Several dump() calls wrote multiple documents into one file |
Dump one list, or switch to JSON Lines |
TypeError when calling json.dump() |
The file was opened in binary mode | Open with "w" and encoding="utf-8" |
UnicodeDecodeError on load |
The file is not encoded in UTF-8 | Open with the encoding that was actually used, or re-save the file as UTF-8 |
Non-ASCII text appears as u sequences |
ensure_ascii is at its default of True |
Pass ensure_ascii=False when the file is UTF-8 |
| Dictionary keys changed type after a round trip | JSON object keys are always strings, so integer keys become strings | Store keys as strings from the start |
Objects that JSON cannot store directly
JSON natively represents objects, arrays, strings, numbers, booleans, and null. Python lists and dictionaries with those kinds of values work directly. Class instances, dates, and sets do not. Passing them to json.dump() raises TypeError unless you supply a conversion strategy.
Best Value
The most direct approach is a default function, which the encoder calls for any object it cannot serialize:
import json
from datetime import date
class Task:
def __init__(self, name, due):
self.name = name
self.due = due
def encode(obj):
if isinstance(obj, Task):
return {"name": obj.name, "due": obj.due.isoformat()}
raise TypeError(f"Cannot serialize {type(obj).__name__}")
with open("tasks.json", "w", encoding="utf-8") as f:
json.dump([Task("Write draft", date(2026, 10, 9))], f, default=encode, indent=2)
Loading does not reverse this automatically. Your code must read the dictionary back and construct the Task object, including converting the date string with date.fromisoformat().
Reading untrusted input safely
The json module reference warns that parsing malicious input may consume considerable CPU and memory, and recommends limiting the size of the data. This is a resource-exhaustion risk. It is not the same as the code-execution risk associated with pickle, which is covered below. The module does not set a limit for you, so choose one based on the largest file your application should accept:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteimport json
import os
MAX_BYTES = 5 * 1024 * 1024 # application-chosen limit
def load_limited(path):
if os.path.getsize(path) > MAX_BYTES:
raise ValueError(f"{path} exceeds {MAX_BYTES} bytes")
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
JSON or pickle
Both modules serialize Python data, but they suit different situations. The choice depends mainly on who reads the data and where it comes from.
| Criterion | JSON | pickle |
|---|---|---|
| Interoperability | A common interchange format read by many applications and languages | Specific to Python |
| Data shape | Objects, arrays, strings, numbers, booleans, and null; other types need conversion code | Can represent many Python objects directly |
| Trust | Parsing does not execute code, but untrusted input still needs size limits and error handling | The Python tutorial warns that deserializing malicious pickle data can execute code; never load untrusted pickle data |
| Readability | Text you can open and edit | Binary data |
For configuration files, exported data, or anything shared with other systems, use JSON. Reserve pickle for trusted, Python-only data that you produced yourself and that must preserve Python types.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




