44

According to the its documentation csv.writer should use '\r\n' as lineterminator by default.

import csv

with open("test.csv", "w") as f:
    writer = csv.writer(f)

    rows = [(0,1,2,3,4),
           (-0,-1,-2,-3,-4),
           ("a","b","c","d","e"),
           ("A","B","C","D","E")]           

    print writer.dialect.lineterminator.replace("\r", "\\r").replace("\n", "\\n")
    writer.writerows(rows)
    print writer.dialect.lineterminator.replace("\r", "\\r").replace("\n", "\\n")

This prints

\r\n
\r\n

as expected. But, the created csv-file uses the lineterminator '\r\r\n'

0,1,2,3,4

0,-1,-2,-3,-4

a,b,c,d,e

A,B,C,D,E

Is this a bug or is there something wrong in my usage of csv.writer?

Python version:

ActivePython 2.6.2.2 (ActiveState Software Inc.) based on Python 2.6.2 (r262:71600, Apr 21 2009, 15:05:37) [MSC v.1500 32 bit (Intel)] on win32

on Windows Vista

smci
  • 26,085
  • 16
  • 96
  • 138
wierob
  • 4,159
  • 1
  • 23
  • 26

3 Answers3

69

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')
Blairg23
  • 8,642
  • 5
  • 61
  • 61
John Machin
  • 75,436
  • 11
  • 125
  • 178
26

Unfortunately, it's a bit different with the csv module for Python 3, but this code will work on both Python 2 and Python 3:

if sys.version_info >= (3,0,0):
    f = open(filename, 'w', newline='')
else:
    f = open(filename, 'wb')
Dave Burton
  • 2,552
  • 25
  • 18
  • 3
    I believe this is is the only solution that works on both Python 2 and 3, both Windows and Linux, and generate files that adhere to the CSV standard of `\r\n` regardless of platform. – MestreLion Feb 10 '18 at 07:45
  • Yes, this should be the accepted answer. Unwanted newlines in `csvwriter` is a notorious pain in Python. – smci Jul 31 '18 at 08:27
  • This is not working for me on either Python 2 or 3, on Linux/Mac. Its still outputing Windows style newlines. – user5359531 Oct 15 '18 at 15:49
  • That is what it is supposed to do, user5359531. The .csv file format is supposed to consist of lines (records) terminated with Windows-style newlines: "\r\n" If it omitted the \r that would be an error. – Dave Burton Oct 16 '18 at 18:17
23

To change the line terminator in Python 2.7 csv writer use

writer = csv.writer(f, delimiter = '|', lineterminator='\n')

This is a much simpler way to change the default delimiter from \r\n.

Jason Callahan
  • 456
  • 5
  • 6
  • It works and is simple!! I'm using DictWriter to stdout --- so the above solutions aren't really appropriate or add extra overhead. – ripvlan Oct 20 '16 at 20:06
  • 1
    While this works for python 2 and 3 on windows, it creates non-standard files on Linux machines: As per specification CSV files _should_ end lines with `\r\n` regardless of platform, not `\n`. – MestreLion Feb 10 '18 at 07:43
  • 1
    Good point, but sometimes it is necessary to violate standards to complete a specific task. – Jason Callahan Mar 06 '18 at 17:18
  • The CSV spec does not matter if you were never writing .csv files in the first place, e.g. .tsv or other delimited text formats, which in my experience is far more common than actually writing .csv. – user5359531 Oct 15 '18 at 15:58