在写入百万行 csv 文件时计算 md5 - 无需将其读入内存



计算 md5 需要字节流才能通过。我假设可以在写入一百万行时将 csv.writer 拦截为字节流。在下面的 py 代码中,写入了一百万行,如何在不仅为 md5 将文件读入内存的情况下计算 md5?

def query2csv(connection, fileUri, sqlQuery, args):
import csv
tocsvfile = open(fileUri, 'w+')
writer = csv.writer(tocsvfile, delimiter=',', quotechar='"') # , quoting=csv.QUOTE_MINIMAL
#As a huge blob goes into writer, pass through, md5 how?
# I do not want to read the huge file through memory just to compute md5
with connection.cursor() as cur:
cur.execute(sqlQuery, args)
column_names = list(map(lambda x: x[0], cur.description))
writer.writerow(column_names)
writer.writerows(__batch_rows(cur))

来自 csv.writer 的文档(强调我的(:

csv.writer(csvfile, dialect='excel', **fmtparams)

返回一个编写器对象,负责将用户的数据转换为给定类似文件的对象的分隔字符串。csvfile可以是具有write()方法的任何对象。如果 csvfile 是文件对象,则应使用newline=''打开它。

因此,我们可以拦截对.write()的调用,并将数据馈送到MD5流中,同时还将其传递给真实文件。最干净的方法是使用write方法定义一个类,该方法只调用一些函数(即一个用于 MD5 流,一个用于文件对象(:

import csv
import hashlib
class WriterTee:
def __init__(self, *outs):
self.outs = outs
def write(self, s):
for f in self.outs:
f(s)
def query2csv(connection, fileUri, sqlQuery, args):
md5 = hashlib.md5()
with open(fileUri, 'w+', newline='') as tocsvfile, connection.cursor() as cur:
tee = WriterTee(
tocsvfile.write,
lambda s: md5.update(s.encode())
)
writer = csv.writer(tee, delimiter=',', quotechar='"')
cur.execute(sqlQuery, args)
column_names = list(map(lambda x: x[0], cur.description))
writer.writerow(column_names)
writer.writerows(__batch_rows(cur))
return md5.hexdigest()

我还进行了一些其他更改,以管理with块中的两个资源,并按照文档所说的使用newline=''


顺便说一下,如果您有选择,我建议不要将MD5用于任何目的。MD5并不安全,密码学家自1996年以来一直建议不要使用它。即使你认为安全属性与应用程序无关,使用安全哈希算法也没有缺点,并且无论选择哪种算法,hashlibAPI 都是相同的。

最新更新