问题 2.7 CSV模块需要unicode,但不需要unicode


csvfile_ = open(finishedFileName+num+".csv","w",newline='')
writ = csv.writer(csvfile_, dialect='excel')
firstline = unicode(str(firstline))
try:
    writ.writerow(firstline)
except TypeError:
    print firstline
    print type(firstline)
    raise

我得到了 TypeError: must be unicode, not str 用这个代码。当我打印出第一线的类型时 <type 'unicode'>。当我打印第一行时,我明白了 ['project_number', 'project_location'](列表比这长,但它继续以那种风格。)

这个程序在python 3.3中运行良好。我用3to2移植它,从我这样做,从unix切换到windows。

如何使这个程序顺利写入?

注意:根据官方文档,此版本的csv模块不支持Unicode输入,但它告诉我无论如何都要给它输入Unicode。

完全例外

Traceback (most recent call last):
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 382, in <module>
    process(marketingLogExportFileName)
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 123, in process
    writing(csvfile,modified,firstline)
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 114, in writing
    writ.writerow(firstline)
TypeError: must be unicode, not str

如果我拿出代码来制作第一行unicode,我就会得到

Traceback (most recent call last):
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 382, in <module>
    process(marketingLogExportFileName)
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 123, in process
    writing(csvfile_,modified,firstline)
  File "C:\Users\urightswt\Downloads\LogModToConvert.py", line 114, in writing
    writ.writerow(firstline)
TypeError: must be unicode, not str

10472
2017-08-26 17:02


起源

你只看着 例外;去除 TypeError 并查看完整的追溯。 - Martijn Pieters♦
该 csv Python 2.7中的模块记录为 不 支持unicode。 - Martijn Pieters♦
什么是 csvfile_?是用它打开的打开文件对象吗? io 要么 codecs 模块,自动编码Unicode?如果是这样,那就是 那 期望Unicode的文件对象,而不是CSV模块。请告诉我们打开文件对象的代码。 - Martijn Pieters♦
和 open 是从哪里进口的?该 内建的  open() 功能不接受 newline Python 2上的参数。 - Martijn Pieters♦
尝试unicodecsv。它用unicode包装CSV。 - DivinusVox


答案:


不幸, 3to2 用了 io.open() 调用而不是内置的Python 2 open() 功能。这以文本模式打开文件,就像在Python 3上一样,需要Unicode输入。

但是,那 csv 模 不支持Unicode数据;它肯定不会产生Unicode。

你要么必须在Python 2上以二进制模式打开文件:

mode = 'w'
if sys.version_info.major < 3:
    mode += 'b'
csvfile_ = open(finishedFileName + num + ".csv", mode, newline='')

或使用内置 open() 打电话给:

csvfile_ = open(finishedFileName + num + ".csv", 'wb')

你必须使用的地方 'wb' 无论如何作为模式。

如果您尝试写出unicode数据,则必须对该数据进行编码 之前 将它传递给 csv.writer() 目的。该 csv 模块示例部分 包括在编写之前使用Unicode进行编码的代码。


15
2017-08-26 17:19



我试图编写一个CSV处理程序,它应该运行Python 2或Python 3,我发现这个答案(通过搜索引擎找到)是有帮助的。我很惊讶成为第一个赞成它的用户。 - Anthony Geoghegan
可能是你错过了 from future.builtins import open 在第一个片段?我认为 newline 是不是在Python 2中打开。 - Martin Thoma
@moose:这就是答案的全部要点;另见关于这个问题的评论。进口是 from io import open; future_builtins 不包括 open。我提供了制作代码的选项 3to2 兼容。 - Martijn Pieters♦
@moose:换句话说:in Python 3 你没有进口声明 open() 呼叫;它是 3to2 可以添加的工具。 - Martijn Pieters♦


我有open()和csv的相同问题。朋友给了我解决方案,即使用open_output()而不是open()。 open_output()默认为“wb”而不是文本。


0
2017-12-19 17:37





使用'w'或'wb'的Martijn Pieters的解决方案似乎不起作用,因为换行参数。我个人得到了一个ValueError。

ValueError: binary mode doesn't take a newline argument

我希望,我真的不明白 io 忽略它而不是引发异常。 在python 2和3上唯一适用于我的解决方案是:

if sys.version_info.major < 3:
    open(my_csv_file, 'rb')
else:
    open(my_csv_file, 'r', newline='')

打开大量文件时可能会变得非常沉重的解决方案。 Martijn解决方案在这方面更加清洁,只要它能够起作用!

编辑: 我认为在开发需要读/写文件的包时,最干净的工作解决方案是创建一个小的实用程序函数,可以在包中随处调用:

import sys
import io

def open_csv_rb(my_file):
    if sys.version_info[0] < 3:
        return io.open(my_file, 'rb')
    else:
        return io.open(my_file, 'r', encoding='utf8')

def open_csv_wb(my_file):
    if sys.version_info[0] < 3:
        return io.open(my_file, 'wb')
    else:
        return io.open(my_file, 'w', newline='', encoding='utf8')

0
2017-07-11 12:27