【问题标题】:Python importing .csv files in utf-8 or cp1252Python 在 utf-8 或 cp1252 中导入 .csv 文件
【发布时间】:2019-03-13 17:03:53
【问题描述】:

不久前,我向question 询问了有关处理带有特殊字符的 .csv 文件的导入问题。当时我有兴趣解决 90% 的问题,但现在我又回来解决最后 10% 的问题了。

基本上和以前一样设置:

  1. 许多输入文件
  2. 所有.csv
  3. 新:现在我想在某些输入中保留特殊字符。但是,我无法控制所有输入文件的格式,因此我需要处理混合文件。当我想要使用不同的编码格式时,我尝试的解决方案是传递一个关键字参数。

代码如下:

import csv
import unicodecsv
#<Lots of other declarations and initialization>

def _csv_dict(self, file,index_field, ScrubMe, **kwargs):

#some irrelevant initialization stuff here.

    if 'formatting' in kwargs:
        formatting = kwargs['formatting']
    else:
        formatting =  None #cp1252 is OS default

    with open(file, encoding=formatting, errors='ignore') as f: #newline = '',
        if formatting == None:
            reader = csv.DictReader(f, dialect = 'excel')
        else: #assume for now UTF-8 is the only other supported format
            reader = unicodecsv.DictReader(f, dialect = csv.excel)

        for line in reader:
            <do some stuff - it's mostly building dictionaries, but I
generally edit the data to only keep the stuff I care about and do a little
data transformation to standard formats >

上面的结果是,如果我传递一个保存为本地编解码器的 .CSV 的 Excel 文件,则导入工作。但是,调用包含格式='utf-8' 关键字 arg 的 unicodecsv 文件会崩溃

错误消息表明我在沿线某处传递了错误类型的对象。这发生在我第一次尝试从 UTF-8 文件中读取一行时

File 
"C:\Users\<me>\AppData\Local\Programs\Python\Python37\lib\site-
packages\unicodecsv\py3.py", line 51, in <genexpr>
f = (bs.decode(encoding, errors=errors) for bs in f)
AttributeError: 'str' object has no attribute 'decode'

根据我的阅读,UTF-8 实际上是制表符分隔而不是逗号分隔,但我“认为”它应该以相同的方式工作。

我觉得我可能搞砸了一些非常简单的事情,但我已经花了足够多的时间来寻找似乎适合寻求帮助的时间。提前感谢您的任何建议。

【问题讨论】:

  • 嗯,我进步了一点。错误消息中的 bs.decode() 显然不是关于 Python 能够解码我要求它执行的 BS。它希望我以二进制模式打开文件。我仍然没有工作。我遇到了一个关键错误。文件顶部似乎有一些标题信息,而 unicode csvReader 处理不正确。
  • 标头原来是一个 UTF-16 字节顺序标记。这让我很困惑,因为我要求 Excel 保存为 UTF-8 .csv。我尝试只读取两个字节的标头,但它显然希望有一个标头,并且出现意外字节的错误。我尝试使用 UTF-16 编码设置为阅读器打开文本文件。这使我所有的文字都变得难以阅读。到目前为止,最接近正确的是打开是否打开(文件,'rb')并且阅读器上的编码是'utf-8',但它会破坏我的第一个键与 BOM。
  • 在 Python 3 中不需要 unicodecsv。std-lib csv 模块在此处使用 (Unicode) 字符串。
  • 我的源文件是带有“另存为 .csv UTF-8”的 Excel。也许我做错了什么,但如果我使用标准的 .csv,它会因为 BOM 而破坏第一个键。我敢打赌,如果数据是从文本编辑器而不是 Excel 保存的,它会起作用。具有讽刺意味的是,Excel 并不能很好地重新摄取这些数据。
  • 听到 Excel 在正确解码文本数据方面表现不佳,我不会感到惊讶。但是,如果您使用 Python 3,这与您不需要(甚至不应该)使用 unicodecsv 包这一事实完全无关。使用正确的编码以文本模式打开文件,一切都应该顺利通过 std-lib csv 模块(前提是您没有损坏的数据)。

标签: python python-3.x csv file-io utf-8


【解决方案1】:

我正在替换我最初的答案,因为我有很多事情要做,我花了一段时间来解开它们。

1) @lenz 是正确的。在 Python 3 中,没有必要使用 unicodecsv.DictReader。让我感到困惑的部分原因是实现上的差异。

a) 对于 Python 2 中较旧的 unicodecsv.DictReader:

kw_args={'errors' : None}
with open(filename, 'rb', **kw_args) as file:
    reader = unicodecsv.DictReader(file, dialect = csv.excel, encoding='utf_8_sig' )

b) 对于 Python 3 csv.DictReader

kw_args={'newline' : '','errors' : None,'encoding' : 'utf_8_sig'}
with open(filename, 'r', **kw_args) as file:
    reader = csv.DictReader(file, dialect = csv.excel )

总结差异

  • 文件打开模式现在是文本而不是字节
  • 由于不同的打开方法,编解码器可以/应该在文件打开与 DictReader 中指定
  • 换行参数也只对以文本形式打开的文件有效。

2) 因为我的 UTF-8 文件是由 Excel 生成的,所以文件顶部有一个 utf_16_le 样式的 BOM。唯一适用于此的编码是“utf_8_sig”。

3) 由于 SQL Server 正在下游读取我的输出文件,因此输出编解码器需要为“utf_16_le”,否则 SQL Server 无法识别。

4) 另外,因为目标是 SQL Server,所以我必须在文件顶部手动插入 BOM。

csvfile.write('\uFEFF') 
writer.writeheader()

如果您在 Excel 中打开上述输出文件,它将不再按列显示,但 SQL Server(实际上是 SSIS)现在知道如何读取文件。

5) 只是为了再逗我一点,有人在一些记录中包含 '\n'。使用 Excel 作为源和目标,这不是问题,但它适用于 SSIS。我的解决方案:

for r in record_list:
    temp={}
    for k,v in r.items():

        if isinstance(v,str):
            temp[k] = v.replace('\n',' ')
        else:
            temp[k] = v
    writer.writerow(temp) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 2012-11-18
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    相关资源
    最近更新 更多