Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I preserve line endings when reading and writing a text file?

Quick answer

In Python, open a copied text file with newline='' when reading so \n, \r, and \r\n are returned untranslated. Keep those endings in the text, and open the output with newline='' too, so writing does not translate \n characters. Choose an encoding appropriate for the sample, and inspect the output’s line endings afterward. Reading with untranslated endings alone is not enough if later code changes or normalizes them. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I need to edit a text file but keep its existing line endings. What is the important Python setting?

Geez

Use newline='' when opening the copied sample for both reading and writing. In text mode, Python’s default newline=None recognizes \n, \r, and \r\n on input but returns each as \n. That makes different original endings indistinguishable in the text you read. With newline='', Python still recognizes those line boundaries but returns their ending characters untranslated. On output, newline=None translates written \n characters to the system line separator; newline='' disables that translation. [S1]

The setting does not stop your own code from changing the text. If you call a method that normalizes line breaks, or rebuild the file using a different separator, the original pattern can still be lost. Work on a copy, retain the ending characters, and check the result.

Follow-up question

Can you show a small read-and-write example and make clear where I should put my filenames?

Geez

Here is a minimal copy-based example. Replace the bracketed filenames and choose an encoding appropriate for your sample. Encoding and newline handling are separate settings; this example does not determine which encoding your file uses. [S1]

from pathlib import Path

source = Path("[copied sample path]")
destination = Path("[output path]")

with source.open("r", encoding="[appropriate encoding]", newline="") as f:
    text = f.read()

# Make any intended edits without normalizing line endings.

with destination.open("w", encoding="[appropriate encoding]", newline="") as f:
    f.write(text)

For a preservation test with no intended edits, leave text untouched. The output is a separate file, so you can compare it with the copied input without overwriting the original.

Follow-up question

How do I check whether the copy kept a mixture such as Windows-style and Unix-style endings?

Geez

Inspect the text using repr() so line-ending characters are visible rather than appearing as ordinary layout. For example, the illustrative string "first\r\nsecond\nthird\r" contains three different endings. You can count the characters in the read text like this:

print(repr(text))
print("CRLF:", text.count("\r\n"))
print("LF:", text.count("\n") - text.count("\r\n"))
print("CR:", text.count("\r") - text.count("\r\n"))

Run the same check on the copied input and the output, reading each with newline=''. Matching visible text and counts is a useful check for this example, but it is not a byte-for-byte comparison: text decoding and re-encoding can affect bytes, and this method does not establish that every other file property stayed unchanged. For byte-level control, Python’s documentation points to binary I/O. [S1]

Follow-up question

What should I do if I only want to change a word, and what are the easy mistakes to avoid?

Geez

Make the narrow edit on the text you read with newline='', then write that text using newline='' as well. A simple string replacement can illustrate the approach, but first ensure the target is the intended text and that your change does not include or replace line-ending characters:

text = text.replace("[old word]", "[new word]")

Avoid reading with the default newline handling when you need to distinguish the original endings. Avoid writing with newline=None when the text contains line breaks you intend to leave untranslated. And do not assume the sample’s encoding: use a suitable, known encoding for both operations. The documentation explains newline translation and notes that encoding must also be selected appropriately; it does not identify the encoding of your particular file or guarantee preservation of all file bytes through text I/O. [S1]

A practical checklist

  • Make a separate working copy; do not test on the only original.

  • Choose an encoding appropriate to the copied sample.

  • Read with newline='' so recognized endings are returned untranslated.

  • Keep the original ending characters while making the intended text edit.

  • Write with newline='' to disable output newline translation.

  • Read the input copy and output with newline='', then compare repr() output or ending counts.

A few more useful answers

Does `newline=''` automatically preserve every aspect of the file?

No. It prevents newline translation in text I/O, but your code can still alter endings, and text encoding is a separate consideration. The described approach is not a guarantee of byte-for-byte preservation. [S1]

Why not use the default newline setting for both operations?

With newline=None, reading converts recognized endings to \n, and writing translates \n to the system line separator. That can lose distinctions in a mixed-ending sample. [S1]

When would binary I/O be more appropriate?

Use it when you need byte-level control rather than text-level newline handling. This guide’s text example does not show how to perform or verify a byte-preserving edit. [S1]

Sources

References used for this guide.

  1. [S1] Python 3.15 io — Core tools for working with streams
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work