【问题标题】:CSV file written with Python has blank lines between each row用 Python 编写的 CSV 文件在每行之间有空行
【发布时间】:2011-03-21 21:05:54
【问题描述】:
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)

此代码读取thefile.csv,进行更改并将结果写入thefile_subset1

但是,当我在 Microsoft Excel 中打开生成的 csv 时,每条记录后都会有一个额外的空白行!

有没有办法让它不放额外的空行?

【问题讨论】:

标签: python windows csv


【解决方案1】:

Python 2 中,使用模式 'wb' 而不是 'w' 打开 outfilecsv.writer 直接将\r\n 写入文件。如果您不以 binary 模式打开文件,它将写入 \r\r\n,因为在 Windows 上 text 模式会将每个 \n 转换为 \r\n

Python 3 中,所需的语法发生了变化,csv 模块现在可以使用文本模式 'w',但还需要 newline=''(空字符串)参数来禁止 Windows 行转换(请参阅下面的文档链接)。

示例:

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

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

文档链接

【讨论】:

  • 无论如何@Mark Tolonen 的回答确实解决了许多与保存标准(不使用 csv)文本文件时添加的额外行相关的问题。
  • 为了兼容 2.6/2.7 和 3,您可以使用 io.opennewlines 参数。如果您仍在使用 2.x 编写代码,那么这似乎是一个更好的选择,因为它是向前兼容的。
  • @jpmc26 通常这是个好建议,但 csv 模块无法与 io.open 一起正常工作。有一个适用于 Python 2.7 的 unicodecsv 3rd 方模块效果更好。
  • 知道为什么newline='' 技巧在带有 StringIO 或 TemporaryFile 的 python3 中不起作用吗?
  • @fmoo 定义“不起作用”。他们都按照我期望的方式工作。 StringIO 缓冲将被编码到文件的相同代码点,TemporaryFile 支持newline 参数,因此可以像使用open 一样打开它。使用不起作用的示例程序提出问题。
【解决方案2】:

以二进制模式“wb”打开文件在 Python 3+ 中不起作用。或者更确切地说,您必须在写入数据之前将其转换为二进制。这只是一个麻烦。

相反,您应该将其保持为文本模式,但将换行符覆盖为空。像这样:

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

【讨论】:

    【解决方案3】:

    简单的答案是 csv 文件应始终以二进制模式打开,无论是输入还是输出,否则在 Windows 上会出现行尾问题。特别是在输出时,csv 模块将写入\r\n(标准CSV 行终止符),然后(在文本模式下)运行时将\n 替换为\r\n(Windows 标准行终止符)给出@987654325 的结果@。

    摆弄lineterminator 不是解决办法。

    【讨论】:

    • 您所说的 CSV“标准”是什么?
    • @Dan:我用“标准”作为形容词,而不是名词,意思是“通常”或“普通”。如果您想要一个(名词)标准的近似值,请阅读tools.ietf.org/html/rfc4180
    • 要点是(正如您所暗示的)没有标准。 RFE 是信息性的。虽然 \r\n 在 Windows 上可能是“标准的”,但我确信 Unix 应用程序通常不会这样看。
    • @Dan:没错——没有标准。脚本应该指定他们想要的 lineterminator [应该被命名为 ROWterminator](如果不是默认值)并且仍然使用二进制模式以防脚本在 Windows 上运行,否则“lineterminator”可能会被填满。
    【解决方案4】:

    注意:这似乎不是首选的解决方案,因为在 Windows 系统上添加了额外的行。如python document中所述:

    如果 csvfile 是文件对象,则必须在不同的平台上使用“b”标志打开它。

    Windows 就是这样一个可以发挥作用的平台。虽然如下所述更改行终止符可能已经解决了问题,但可以通过以二进制模式打开文件来完全避免该问题。有人可能会说这种解决方案更“优雅”。在这种情况下,“摆弄”行终止符可能会导致系统之间的代码不可移植,在 unix 系统上以二进制模式打开文件不会产生任何效果。 IE。它会产生跨系统兼容的代码。

    来自Python Docs

    在 Windows 上,“b”附加到模式 以二进制模式打开文件,所以 还有像'rb','wb'这样的模式, 和'r+b'。 Windows 上的 Python 使 文本和二进制的区别 文件;中的行尾字符 文本文件会自动更改 读取或写入数据时稍微。 这个幕后修改为 文件数据适用于 ASCII 文本 文件,但它会损坏二进制数据 像 JPEG 或 EXE 文件中的那样。是 使用二进制模式时非常小心 读取和写入此类文件。在 Unix,附加一个'b'并没有什么坏处 到模式,所以你可以使用它 平台无关的所有二进制文件 文件。

    原创

    作为 csv.writer 可选参数的一部分,如果您获得额外的空白行,您可能需要更改换行符(信息 here)。下面的示例改编自 python 页面 csv docs. 将其从 '\n' 更改为应有的内容。由于这只是在黑暗中解决问题,这可能会或可能不会起作用,但这是我最好的猜测。

    >>> import csv
    >>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
    >>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
    >>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
    

    【讨论】:

    • 我正要发布这个——lineterminator='\n' 在一个简单的测试中为我工作。
    • 我可以这样做>??使用 open('/pythonwork/thefile_subset11.csv', 'w'),lineterminator='\n' 作为输出文件:
    • @I__ :您真的应该开始阅读 Python 文档。德里克给了你链接:docs.python.org/library/csv.html
    • documentationcsv.writercsv.readerdocumentation 自 2010 年发布原始帖子以来已更新。现在建议您在打开文件时使用 newline=''
    【解决方案5】:

    自最初的问题以来的十年中,许多其他答案已经过时了。对于Python3,答案就在documentation

    如果 csvfile 是一个文件对象,应该用newline=''打开它

    footnote有更详细的解释:

    如果未指定 newline='',则嵌入在引用字段中的换行符将无法正确解释,并且在使用 \r\n linendings on write 的平台上将添加额外的 \r。指定 newline='' 应该始终是安全的,因为 csv 模块自己(通用)换行处理。

    【讨论】:

      【解决方案6】:

      我正在写这个答案w.r.t。到 python 3,因为我最初遇到了同样的问题。

      我应该使用 PySerial 从 arduino 获取数据,并将它们写入 .csv 文件。在我的案例中,每次阅读都以'\r\n' 结尾,因此换行符总是分隔每一行。

      就我而言,newline='' 选项不起作用。因为它显示了一些错误,例如:

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

      所以他们似乎不接受这里省略换行符。

      在这里只看到一个答案,我在 writer 对象中提到了行终止符,例如,

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

      这对我来说可以跳过额外的换行符。

      【讨论】:

      • 这是不正确的。 with open('my_file.csv', 'a',newline='') as csvfile: 工作得很好。你的答案的问题是你在这里写的是' '而不是''
      • 可能是这样,在我的系统中它是这样工作的
      【解决方案7】:

      使用下面定义的方法将数据写入 CSV 文件。

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

      只需在open 方法中添加一个额外的newline='' 参数即可:

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

      这将写入 CSV 行而不创建其他行!

      【讨论】:

      • 谢谢! newline='' 非常适合我的应用程序
      【解决方案8】:
      with open(destPath+'\\'+csvXML, 'a+') as csvFile:
          writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
          writer.writerows(xmlList)
      

      "lineterminator='\r'" 允许传递到下一行,两行之间没有空行。

      【讨论】:

        【解决方案9】:

        借用this answer,似乎最干净的解决方案是使用io.TextIOWrapper。我设法为自己解决了这个问题,如下所示:

        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)
        

        上述答案与 Python 2 不兼容。为了兼容,我想只需将所有编写逻辑包装在 if 块中:

        if sys.version_info < (3,):
            # Python 2 way of handling CSVs
        else:
            # The above logic
        

        【讨论】:

        • 这里最好的帖子之一!非常有帮助。在职的。没有更多的cmets。 ;-)
        【解决方案10】:

        在使用 Python 3 时,可以通过使用 codecs 模块来避免空行。如文档中所述,文件以二进制模式打开,因此不需要更改换行符 kwarg。我最近遇到了同样的问题,这对我有用:

        with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
             csv_out_file = csv.DictWriter(out_csv)
        

        【讨论】: