Python 2 CSV Writer Produces Wrong Line Terminator on Windows

Python 2 CSV writer produces wrong line terminator on Windows

In Python 2.x, always open your file in binary mode, as documented. csv writes \r\n as you expected, but then the underlying Windows text file mechanism cuts in and changes that \n to \r\n ... total effect: \r\r\n

From the csv.writer documentation:

If csvfile is a file object, it must be opened with the 'b' flag on platforms where that makes a difference.

There seems to be some reticence about actually uttering the name of the main culprit :-)

Edit: As mentioned by @jebob in the comments to this answer and based on @Dave Burton's answer, to handle this case in both Python 2 and 3, you should do the following:

if sys.version_info >= (3,0,0):
f = open(filename, 'w', newline='')
else:
f = open(filename, 'wb')

CSV in Python adding an extra carriage return, on Windows

Python 3:

The official csv documentation recommends opening the file with newline='' on all platforms to disable universal newlines translation:

with open('output.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
...

The CSV writer terminates each line with the lineterminator of the dialect, which is '\r\n' for the default excel dialect on all platforms because that's what RFC 4180 recommends.



Python 2:

On Windows, always open your files in binary mode ("rb" or "wb"), before passing them to csv.reader or csv.writer.

Although the file is a text file, CSV is regarded a binary format by the libraries involved, with \r\n separating records. If that separator is written in text mode, the Python runtime replaces the \n with \r\n, hence the \r\r\n observed in the file.

See this previous answer.

CSV file written with Python has blank lines between each row

The csv.writer module directly controls line endings and writes \r\n into the file directly. In Python 3 the file must be opened in untranslated text mode with the parameters 'w', newline='' (empty string) or it will write \r\r\n on Windows, where the default text mode will translate each \n into \r\n.

#!python3
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
writer = csv.writer(outfile)

In Python 2, use binary mode to open outfile with mode 'wb' instead of 'w' to prevent Windows newline translation. Python 2 also has problems with Unicode and requires other workarounds to write non-ASCII text. See the Python 2 link below and the UnicodeReader and UnicodeWriter examples at the end of the page if you have to deal with writing Unicode strings to CSVs on Python 2, or look into the 3rd party unicodecsv module:

#!python2
with open('/pythonwork/thefile_subset11.csv', 'wb') as outfile:
writer = csv.writer(outfile)

Documentation Links

  • https://docs.python.org/3/library/csv.html#csv.writer
  • https://docs.python.org/2/library/csv.html#csv.writer

\r' not working as `lineterminator` within Python `csv.writer()`

The shorter answer:

When to use carriage return (CR, \r) vs. line feed (LF, \n) vs. both (CRLF, \r\n) to make a new line appear in a text editor on Windows, Mac, and Linux:

How does '\r' work in lineterminator in writer()??

It works fine in csv.writer(). This really isn't a Python, CSV, or writer problem. This is an operating system historical difference (actually, it's more accurate to state it is a program-specific difference) going back to the 1960s or so.

Or is there another thing happening there?

Yes, this is the one.

Your version of Notepad doesn't recognize a carriage return (\r) as a character used to display new lines, and hence won't display it as such in Notepad. Other text editors, such as Sublime Text 3, however probably would, even on Windows.

Up until about the year 2018 or so, Windows and Notepad required a carriage return + line feed (\r\n) together to display a new line. Contrast this to Mac and Linux, which require only \n.

The solution is to use \r\n for a new line on Windows, and \n alone for a new line on Mac or Linux. You can also try a different text editor, such as Sublime Text, when viewing or editing text files, or upgrade your version of Windows or Notepad, if possible, as somewhere around the year 2018 Windows Notepad started to accept \r alone as a valid old-Mac-style new line char.

(from the OP's comment under this answer):

Then why to give '\r\n'???

When a programmer writes a program, the programmer can make the program do whatever the programmer wants the program to do. When Windows programmers made Windows and Notepad they decided to make the program do nothing if it got a \r, nothing if it got a \n, and to do a new line if it got a \r\n together. It's that simple. The program is doing exactly what the programmers told it to do, because they decided that's how they wanted the program to work. So, if you want a new line in the older (pre-2018) version of Notepad in Windows, you must do what the programmers require you to do to get it. \r\n is it.

This goes back to the days of teletypewriters (read the "History" and "Representation" sections here), and this page about "teleprinters" / "teletypewriters" / "teletype or TTY machines" too:

A typewriter or electromechanical printer can print characters on paper, and execute operations such as move the carriage back to the left margin of the same line (carriage return), advance to the same column of the next line (line feed), and so on.

(source; emphasis added)

The mechanical carriage return button on a teletypewriter (\r now on a computer) meant: "return the carriage (print head) to the beginning of the line" (meaning: the far left side of the page), and the line feed mechanical mechanism on a teletypewriter (\n now on a computer) meant: "roll the paper up one line so we can now type onto the next line." Without the mechanical line feed (\n) action, the carriage return (\r) alone would move the mechanical print head to the far left of the page and cause you to type right back on top of the words you already typed! And without the carriage return mechanical action (\r on a computer), the line feed mechanical action (\n) alone would cause you to just type in the last column at the far right on each new line on the page, never able to return the print head to the left side of the page again! On an electro-mechanical teletypewriter, they both had to be used: the carriage return would bring the print head back to the left side of the page, and the line feed action would move the print head down to the next line. So, presumably, Windows programmers felt it was logical to keep that tradition alive, and they decided to require both a \r\n together to create a new line on a computer, since that's how it had to be done traditionally on an electro-mechanical teletypewriter.

Read below for details.

Details (the longer answer):

I have some ideas of what's going on, but let's take a look. I believe we have two questions to answer:

  1. Is the \r actually being stored into the file?
  2. Is Notepad actually showing the \r, and if not, why not?

So, for #1. Let's test it on Linux Ubuntu 20.04 (Focal Fossa):

This program:

#!/usr/bin/python3

import csv
data = [['fruit','quantity'], ['apple',5], ['banana',7],['mango',8]]
with open('d:\lineter.csv','w') as l:
w = csv.writer(l, delimiter='|', lineterminator='\r')
w.writerows(data)

produces this file: d:\lineter.csv. If I open it in the Sublime Text 3 text editor I see:

fruit|quantity
apple|5
banana|7
mango|8

So far so good. Let's look at the characters with hexdump at the command line:

hexdump -c shows the \r characters, sure enough!

$ hexdump -c d\:\\lineter.csv
0000000 f r u i t | q u a n t i t y \r a
0000010 p p l e | 5 \r b a n a n a | 7 \r
0000020 m a n g o | 8 \r
0000028

You can also use hexdump -C to show the characters in hexadecimal instead, and again, I see the \r in the file as a hex 0d char, which is correct.

Ok, so I boot up Windows 10 Professional in my VirtualBox virtual machine in Linux, and open the same file in Notepad, and....it works too! See screenshot:

Sample Image

But, notice the part I circled which says "Macintosh (CR)". I'm running the latest version of Windows 10 Professional. I'm betting you're using an old version of Notepad which doesn't have this fix, and yours won't say that here. This is because for 33 years Notepad didn't handle Carriage Return, or \r, as a valid line-ending, so it wouldn't display it as such. See here: Windows Notepad fixed after 33 years: Now it finally handles Unix, Mac OS line endings.

Due to historical differences dating back to teletypewriters and Morse code (read the "History" and "Representation" sections here), different systems decided to make their text editors treat line endings in different ways. From the article just above (emphasis added):

Notepad previously recognized only the Windows End of Line (EOL) characters, specifically Carriage Return (CR, \r, 0x0d) and Line Feed (LF, \n, 0x0a) together.

For old-school Mac OS, the EOL character is just Carriage Return (CR, \r, 0x0d) and for Linux/Unix it's just Line Feed (LF, \n, 0x0a). Modern macOS, since Mac OS X, follows the Unix convention.

So, what we have here is the following displayed as a newline in a text editor:

  1. Old-school Mac: CR (\r) only
  2. Windows Notepad up until ~2018: CR & LF together (\r\n)
  3. Linux: LF (\n) only
  4. Modern Mac: LF (\n) only
  5. Modern Windows Notepad (year ~2018 and later): any of the scenarios above.

So, for Windows, just stick to always using \r\n for a newline, and for Mac or Linux, just stick to always using \n for a newline, unless you're trying to guarantee old-school (i.e., pre-2019 :)) Windows compatibility of your files, in which case you should use \r\n for newlines as well.


Note, for Sublime Text 3, I just searched the preferences in PreferencesSettings and found this setting:

    // Determines what character(s) are used to terminate each line in new files.
// Valid values are 'system' (whatever the OS uses), 'windows' (CRLF) and
// 'unix' (LF only).
"default_line_ending": "system",

So, to use the convention for whatever OS you're running Sublime Text on, the default is "system". To force 'windows' (CRLF) line endings when editing and saving files in Sublime Text, however, use this:

"default_line_ending": "windows",

And to force Unix (Mac and Linux) LF-only line ending settings, use this:

"default_line_ending": "unix",

In the Notepad editor, I can find no such settings to configure. It is a simple editor, catering for 33 years to Windows line endings only.

Additional Reading:

  1. https://en.wikipedia.org/wiki/Teleprinter
  2. https://en.wikipedia.org/wiki/Newline#History
  3. Is a new line = \n OR \r\n?
  4. Why does Windows use CR LF?
  5. [I still need to read & study] Unix & Linux: Why does Linux use LF as the newline character?
  6. [I still need to read & study] Retrocomputing: Why is Windows using CR+LF and Unix just LF when Unix is the older system?

Does Python csv writer always use DOS end-of-line characters?

You can give your writer instance a custom lineterminator argument in the constructor:

writer = csv.writer(f, lineterminator="\n")

csv.write skipping lines when writing to csv

Solution is to specify the "lineterminator" parameter in the constructor:

file = open('P:\test.csv', 'w')

fields = ('ItemID', 'Factor', 'FixedAmount')
wr = csv.DictWriter(file, fieldnames=fields, lineterminator = '\n')

wr.writeheader()
wr.writerow({'ItemID':1, 'Factor': 2, 'FixedAmount':3})
file.close()

erroneous line added while adding new columns python

I had the same problem on Windows (your OS as well, I presume?). CSV and Windows as combination make a \r\r\n at the end of each line (so: double newline).

You need to open the output file in binary mode:

with open('test_out.csv', 'wb') as outfile:

For other answers:

Python's CSV writer produces wrong line terminator

CSV in Python adding an extra carriage return

CSV Reader different outputs on Ubuntu and Windows - Python

You must use wb mode for csv files if you are using Python 2.x:

https://docs.python.org/2/library/csv.html#csv.writer

If csvfile is a file object, it must be opened with the ‘b’ flag on platforms where that makes a difference.

Python: Writing new line to csv in for loop

You have to open your file in binary mode ("ab") before passing them to csv.writer like this:

with open('parameterCombinatons.csv','ab') as csv_file:  #python3 open('parameterCombinatons.csv','a',newline='')


Related Topics



Leave a reply



Submit