706
import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))
  import collections
  counter = collections.defaultdict(int)

  for row in data:
        counter[row[10]] += 1


with open('/pythonwork/thefile_subset11.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[10]] >= 504:
           writer.writerow(row)

This code reads thefile.csv, makes changes, and writes results to thefile_subset1.

However, when I open the resulting csv in Microsoft Excel, there is an extra blank line after each record!

Is there a way to make it not put an extra blank line?

martineau
  • 119,623
  • 25
  • 170
  • 301
Alex Gordon
  • 57,446
  • 287
  • 670
  • 1,062
  • 20
    Please confirm that this happens when you run that code on **Windows** – John Machin Jul 27 '10 at 23:09
  • 2
    Possible duplicate of [Python 2 CSV writer produces wrong line terminator on Windows](https://stackoverflow.com/questions/1170214/python-2-csv-writer-produces-wrong-line-terminator-on-windows) – John Y Nov 17 '17 at 17:49
  • 1
    See the answer on this thread: https://stackoverflow.com/questions/3348460/csv-file-written-with-python-has-blank-lines-between-each-row/#53577233 – Febin Mathew Dec 02 '18 at 03:59
  • 2
    Wouldn't setting `lineterminator='\n'` as default parameter for the initialization of `csv.writer` solve the problem? Want somebody do a Python 3.10 PR for this? – Basj Nov 30 '20 at 09:18
  • 1
    BTW, here are the official examples: https://docs.python.org/3/library/csv.html?highlight=csv#examples – Basj Nov 30 '20 at 09:28
  • 1
    @Basj yes, lineterminator works great, as you suggested. Also works for stdout, where you don't control the newline setting. – yoyo Dec 12 '22 at 05:56
  • @Basj It solves the problem incorrectly. If `newline=''` is not specified in the `open`, you'd still end up with `\r\n` line endings but it wouldn't double-space the file Excel. But then you don't get the line terminator specified. Changing the default would also break backward compatibility. – Mark Tolonen Mar 13 '23 at 00:56

11 Answers11

1383

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)

If using the Path module:

from pathlib import Path
import csv

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

If using the StringIO module to build an in-memory result, the result string will contain the translated line terminator:

from io import StringIO
import csv

s = StringIO()
writer = csv.writer(s)
writer.writerow([1,2,3])
print(repr(s.getvalue()))  # '1,2,3\r\n'   (Windows result)

If writing that string to a file later, remember to use newline='':

# built-in open()
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as f:
    f.write(s.getvalue())

# Path's open()
with Path('/pythonwork/thefile_subset11.csv').open('w', newline='') as f:
    f.write(s.getvalue())

# Path's write_text() added the newline parameter to Python 3.10.
Path('/pythonwork/thefile_subset11.csv').write_text(s.getvalue(), newline='')

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

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • 2
    Anyway the @Mark Tolonen's answer did resolved many questions related to the extra line(s) added when saving a standard (no csv used) text file. – dlewin Sep 24 '15 at 09:32
  • 2
    For compatibility between 2.6/2.7 and 3, you can use [`io.open`](https://docs.python.org/2/library/io.html#io.open) with the `newlines` argument. If you're still writing in 2.x, that seems like a better choice anyway since it's forward compatible. – jpmc26 Sep 27 '17 at 18:49
  • @jpmc26 Normally that's good advice, but the csv module doesn't work properly with `io.open`. There is a `unicodecsv` 3rd party module for Python 2.7 that works better. – Mark Tolonen Feb 26 '18 at 22:26
  • 2
    Any idea why the `newline=''` trick doesn't work in python3 with StringIO or TemporaryFile? – fmoo Apr 18 '20 at 03:17
  • @fmoo define "doesn't work". They both work they way I expect. `StringIO` buffers the same code points that would be encoded to a file, and `TemporaryFile` supports the `newline` parameter, so it can be opened as with `open`. Ask a question with a sample program that isn't working. – Mark Tolonen Apr 18 '20 at 09:27
  • When using StringIO, I would get the extra `\x0d` in the payload, even in [code](https://pastebin.com/pvYNhKBH) using `newline=''` on `StringIO`. This was actually related to [Path.write_text()](https://docs.python.org/3/library/pathlib.html#pathlib.Path.write_text). [bugs.python.org](https://bugs.python.org/issue23706) notes the lack of `newline` parameter in this API. A workaround is to use `.write_bytes(f.getvalue().encode('utf-8')` instead. – fmoo Apr 18 '20 at 16:53
  • @fmoo The whole point of using `newline=''` is that the csv module *intentionally* controls the newline. The `csv` module is writting \r\n explicitly so of course StringIO is going to contain it. If you don't want it, override the `lineterminator` default when creating the `csv.writer`. – Mark Tolonen Apr 18 '20 at 18:23
  • 1
    My ultimate point is that if you use `csv` with `pathlib.Path` instead of `open`, the current answer results in `\r\r\n` newlines, even if you pass `newline=''` to the `StringIO`, and the solution is nonobvious. Now people can read these comments and find an answer and learn more about the nuance. Overriding `lineterminator` works, though it overrides the `flavor` settings, spites `csv`s encoding intentions, and muddies encoding across modules. Strangely, `csv.writer()` in Python 3 does *not* work with `BytesIO`, which I would expect it to, since it uses `\r\n` line endings by default. – fmoo Apr 18 '20 at 23:20
  • @fmoo It's not strange, it's *repaired*. Python 2's csv module working with bytes and it was broken when dealing with Unicode. It sounds like `Path` is somewhat broken since it can't suppress \n to \r\n translation without supporting `newline`. – Mark Tolonen Apr 19 '20 at 09:29
  • @fmoo Learned that `Path.write_text` added the `newline=''` parameter in Python 3.10, and also found `Path.open` supported it all along. Updated answer to reflect that. – Mark Tolonen Mar 13 '23 at 00:38
89

Opening the file in binary mode "wb" will not work in Python 3+. Or rather, you'd have to convert your data to binary before writing it. That's just a hassle.

Instead, you should keep it in text mode, but override the newline as empty. Like so:

with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
David Maddox
  • 1,884
  • 3
  • 21
  • 32
15

Note: It seems this is not the preferred solution because of how the extra line was being added on a Windows system. As stated in the python document:

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

Windows is one such platform where that makes a difference. While changing the line terminator as I described below may have fixed the problem, the problem could be avoided altogether by opening the file in binary mode. One might say this solution is more "elegent". "Fiddling" with the line terminator would have likely resulted in unportable code between systems in this case, where opening a file in binary mode on a unix system results in no effect. ie. it results in cross system compatible code.

From Python Docs:

On Windows, 'b' appended to the mode opens the file in binary mode, so there are also modes like 'rb', 'wb', and 'r+b'. Python on Windows makes a distinction between text and binary files; the end-of-line characters in text files are automatically altered slightly when data is read or written. This behind-the-scenes modification to file data is fine for ASCII text files, but it’ll corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files. On Unix, it doesn’t hurt to append a 'b' to the mode, so you can use it platform-independently for all binary files.

Original:

As part of optional paramaters for the csv.writer if you are getting extra blank lines you may have to change the lineterminator (info here). Example below adapated from the python page csv docs. Change it from '\n' to whatever it should be. As this is just a stab in the dark at the problem this may or may not work, but it's my best guess.

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Derek Litz
  • 10,529
  • 7
  • 43
  • 53
  • I was about to post about this -- lineterminator='\n' worked for me in a simple test. – Dan Breslau Jul 27 '10 at 22:39
  • can i do this>?? with open('/pythonwork/thefile_subset11.csv', 'w'),lineterminator='\n' as outfile: – Alex Gordon Jul 27 '10 at 22:41
  • 1
    @I__ : You *really* should start perusing the Python docs. Derek gave you the link : http://docs.python.org/library/csv.html – Dan Breslau Jul 27 '10 at 22:49
  • 1
    The [documentation](https://docs.python.org/3/library/csv.html#csv.writer) for `csv.writer` and `csv.reader` has been updated since the original post back in 2010. It now recommends using `newline=''` when you open the file. – AustinDahl Mar 31 '21 at 01:24
15

A lot of the other answers have become out of date in the ten years since the original question. For Python3, the answer is right in the documentation:

If csvfile is a file object, it should be opened with newline=''

The footnote explains in more detail:

If newline='' is not specified, newlines embedded inside quoted fields will not be interpreted correctly, and on platforms that use \r\n linendings on write an extra \r will be added. It should always be safe to specify newline='', since the csv module does its own (universal) newline handling.

AustinDahl
  • 832
  • 7
  • 9
12

The simple answer is that csv files should always be opened in binary mode whether for input or output, as otherwise on Windows there are problems with the line ending. Specifically on output the csv module will write \r\n (the standard CSV row terminator) and then (in text mode) the runtime will replace the \n by \r\n (the Windows standard line terminator) giving a result of \r\r\n.

Fiddling with the lineterminator is NOT the solution.

John Machin
  • 81,303
  • 11
  • 141
  • 189
  • 1
    What is this CSV "standard" of which you speak? – Dan Breslau Jul 27 '10 at 23:30
  • 3
    @Dan: I used "standard" as an adjective, not a noun, meaning "usual" or "commonplace". If you want an approximation to a (noun) standard, read http://tools.ietf.org/html/rfc4180 – John Machin Jul 28 '10 at 00:26
  • 3
    Point is (as you imply) that there is no standard. That RFE is Informational. While \r\n may be "standard" on Windows, I'm sure Unix applications typically don't see it that way. – Dan Breslau Jul 28 '10 at 02:51
  • 2
    @Dan: That is correct -- there is no standard. Scripts should specify the lineterminator [should have been named ROWterminator] that they want (if not the default) and still use binary mode in case the script is run on Windows otherwise the "lineterminator" may be stuffed up. – John Machin Jul 28 '10 at 03:28
  • Fiddling with lineterminator worked great for me (on Windows). And had the added benefit of working for a csv writer using stdout. – yoyo Dec 12 '22 at 05:54
  • @yoyo - those comments from 2010 are talking about python2 and different behavior – yzorg Dec 15 '22 at 16:20
8

Use the method defined below to write data to the CSV file.

open('outputFile.csv', 'a',newline='')

Just add an additional newline='' parameter inside the open method :

def writePhoneSpecsToCSV():
    rowData=["field1", "field2"]
    with open('outputFile.csv', 'a',newline='') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(rowData)

This will write CSV rows without creating additional rows!

Febin Mathew
  • 991
  • 1
  • 11
  • 20
5
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

The "lineterminator='\r'" permit to pass to next row, without empty row between two.

SheRa
  • 59
  • 1
  • 1
4

I'm writing this answer w.r.t. to python 3, as I've initially got the same problem.

I was supposed to get data from arduino using PySerial, and write them in a .csv file. Each reading in my case ended with '\r\n', so newline was always separating each line.

In my case, newline='' option didn't work. Because it showed some error like :

with open('op.csv', 'a',newline=' ') as csv_file:

ValueError: illegal newline value: ''

So it seemed that they don't accept omission of newline here.

Seeing one of the answers here only, I mentioned line terminator in the writer object, like,

writer = csv.writer(csv_file, delimiter=' ',lineterminator='\r')

and that worked for me for skipping the extra newlines.

Debanjan Dey
  • 115
  • 2
  • 15
  • 5
    This is incorrect. `with open('my_file.csv', 'a',newline='') as csvfile:` works absolutely fine. The problem with your answer is that here you're writing `' '` instead of `''` – Nina Sep 25 '18 at 15:50
  • May be so, in my system it worked like that – Debanjan Dey Dec 01 '20 at 14:37
2

Borrowing from this answer, it seems like the cleanest solution is to use io.TextIOWrapper. I managed to solve this problem for myself as follows:

from io import TextIOWrapper

...

with open(filename, 'wb') as csvfile, TextIOWrapper(csvfile, encoding='utf-8', newline='') as wrapper:
    csvwriter = csv.writer(wrapper)
    for data_row in data:
        csvwriter.writerow(data_row)

The above answer is not compatible with Python 2. To have compatibility, I suppose one would simply need to wrap all the writing logic in an if block:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic
phantom-99w
  • 928
  • 1
  • 11
  • 22
0

I used writerow

def write_csv(writer, var1, var2, var3, var4):
    """
    write four variables into a csv file
    """
    writer.writerow([var1, var2, var3, var4])      
        
numbers=set([1,2,3,4,5,6,7,2,4,6,8,10,12,14,16])
rules = list(permutations(numbers, 4))
#print(rules)
selection=[]
with open("count.csv", 'w',newline='') as csvfile:
    writer = csv.writer(csvfile)

    for rule in rules:
        number1,number2,number3,number4=rule
        if ((number1+number2+number3+number4)%5==0):
            #print(rule)
            selection.append(rule)
            write_csv(writer,number1,number2,number3,number4)
Golden Lion
  • 3,840
  • 2
  • 26
  • 35
-1

When using Python 3 the empty lines can be avoid by using the codecs module. As stated in the documentation, files are opened in binary mode so no change of the newline kwarg is necessary. I was running into the same issue recently and that worked for me:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)
anothernode
  • 5,100
  • 13
  • 43
  • 62
JBa
  • 29
  • 4