【问题标题】:Python: csv to pickle representation, back to csv messes with file contentPython:csv到pickle表示,回到csv文件内容混乱
【发布时间】:2021-05-04 19:40:34
【问题描述】:

我正在尝试腌制一个 csv 文件,然后将其腌制表示转回 csv 文件。

这是我想出的代码:

from pathlib import Path
import pickle, csv

csvFilePath = Path('/path/to/file.csv')

pathToSaveTo = Path('/path/to/newFile.csv')

csvFile = open(csvFilePath, 'r')
f = csvFile.read() 
csvFile.close() 

f_pickled = pickle.dumps(f) 


f_unpickled = pickle.loads(f_pickled) 

#save unpickled csv file
new_csvFile = open(pathToSaveTo, 'w')
csvWriter = csv.writer(new_csvFile)
csvWriter.writerow(f_unpickled)
new_csvFile.close()

newFile.csv 已创建,但其内容存在两个问题:

  1. 现在每个字符之间都有一个逗号。
  2. 现在每行后面都有一对引号。

我需要对我的代码进行哪些更改才能获得 file.csv 的精确副本?

【问题讨论】:

  • 您的输入文件似乎不是逗号分隔的
  • 虽然在每个“测试”后加逗号确实会产生类似的结果。由于我在每一行中只有一列,因此我认为没有必要在每一行之后放置逗号。

标签: python csv pickle


【解决方案1】:

问题是你正在读取文件的原始文本,f = csvFile.read() 然后,在写入时,你正在输入数据,这是一个单一的文本块,全部在一个字符串中,虽然是一个 CSV @ 987654323@ 对象。 CSV writer 会将字符串视为可迭代,并将每个可迭代元素写入 CSV 单元格。然后,第二行没有数据,过程结束。

您执行的泡菜dumpsloads 只是一个无操作:那里什么都没有发生,如果有任何问题,那可能是由于您传递给@的对象中有一些不可腌制的对象引用987654327@:当loads 被调用时,你会得到一个异常,并且没有不同的数据。

现在,不告诉你为什么要这样做,以及你为数据计划了哪些中间步骤,很难告诉你:你正在执行两个非操作:读取文件,酸洗和解开它的内容,并将这些内容写回磁盘。

您何时需要将这些数据结构化为行或 CSV 单元格?只需在需要的地方应用适当的转换,就完成了。

如果您希望整个“什么都不做”循环通过实际将 CSV 数据分隔到 Python 中的不同元素中,您可以执行:

from pathlib import Path
import pickle, csv

csvFilePath = Path('file.csv')

pathToSaveTo = Path('newFile.csv')

data = list(csv.reader(open(csvFilePath))) 
# ^consumes all iterations of the reader: each iteration is a row, composed of a list where each cell value is a list elemnt
pickled_data = pickle.dumps(data)
restored_data = pickle.loads(pickled_data)
csv.writer(open(pathToSaveTo, "wt")).writerows(restored_data)

认为在这个 sn-p 中数据是通过 csv.reader 读取的,而不是直接读取的。将其包装在列表调用中会导致在列表项中读取和转换所有行 - 因为阅读器是一个惰性迭代器(否则它不会是可挑选的,因为它依赖于其状态的属性之一是打开文件)

【讨论】:

  • 我最初的想法是通过套接字将 csv 文件从客户端发送到服务器。由于据说腌制 python 对象可以保持对象结构,我认为发送 csv 文件的腌制表示比发送行列表更容易。
  • 不错。因此,“ickled_data”可以通过这种方式传输。代码中的原始 f 变量也是如此 - 尽管您必须将其转换为字节(使用 f.encode('utf-8") s -pickling 可能更方便。请注意发送大通过套接字的数据量(在这种情况下为数百 kbytes)将要求您将信息拆分为各种数据报
  • TL;DR:使用更高级别的协议来为您解决问题:套接字级别太低了,您将不得不重新发明一些轮子;
  • 啊,我明白了。但是,如果我不得不求助于发送所有行的列表,那么在发送之前腌制它有什么好处吗?正如您可能从我最初的问题中猜到的那样,我仍然是初学者,所以我正在努力学习基础知识。出于好奇和进一步研究,什么是合适的更高级别的协议?
【解决方案2】:

我认为问题在于您尝试编写 CSV 文件的方式,酸洗和解酸都很好。如果将 f 与 f_unpickled 进行比较:

if f==f_unpickled:
    print("Same")

这是在我的情况下打印的。如果你打印类型,你会看到有两个字符串。

更好的选择是遵循document style 并一次写入每一行,而不是将整个字符串包含新行。像这样的:

from pathlib import Path
import pickle, csv

csvFilePath = Path('file.csv')

pathToSaveTo = Path('newFile.csv')

rows = []
csvFile = open(csvFilePath, 'r')
with open(csvFilePath, 'r') as file:
    reader = csv.reader(file)
    for row in reader:
        rows.append(row)

# pickle and unpickle        
rows_pickled = pickle.dumps(rows) 
rows_unpickled = pickle.loads(rows_pickled) 
if rows==rows_unpickled:
    print("Same")

#save unpickled csv file
with open(pathToSaveTo, 'w', newline='') as csvfile:
    csvWriter = csv.writer(csvfile)
    for row in rows_unpickled:
        csvWriter.writerow(row)

这在我测试时有效——尽管需要更多地使用行分隔符才能得到最后没有空行。

【讨论】:

  • 实际上,一口气读取文件没有问题-问题是文件被读取为“原始文本”,并通过csv.writer对象写回,这将然后在单个 CSV 单元格中处理每一行
  • 啊,对;原始示例是直接读取文件内容而不是使用阅读器,然后编写器只是转换原始文本(如果我将阅读器循环换成原始阅读代码,它会在新行上打印每个字符,这很有趣)。尽管如此,对于读取整个 CSV 文件并写出整个 CSV 文件,在每行基础上使用实际的读取器和写入器方法似乎是显而易见的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-28
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多