Python csv.DictReader中的行数

Python csv.DictReader中的行数,python,iterator,python-3.x,Python,Iterator,Python 3.x,我有一个csv DictReader对象(使用Python3.1),但我想在迭代它之前知道读取器中包含的行数。如下所示 myreader = csv.DictReader(open('myFile.csv', newline='')) totalrows = ? rowcount = 0 for row in myreader: rowcount +=1 print("Row %d/%d" % (rowcount,totalrows)) 我知道我可以通过遍历阅读器得到总数,

我有一个csv DictReader对象(使用Python3.1),但我想在迭代它之前知道读取器中包含的行数。如下所示

myreader = csv.DictReader(open('myFile.csv', newline=''))

totalrows = ?

rowcount = 0
for row in myreader:
    rowcount +=1
    print("Row %d/%d" % (rowcount,totalrows))
我知道我可以通过遍历阅读器得到总数,但是我无法运行“for”循环。我可以迭代读卡器的副本,但找不到如何复制迭代器

我也可以用

totalrows = len(open('myFile.csv').readlines())
但这似乎是不必要的重新打开文件。如果可能的话,我宁愿从听写器那里得到计数

任何帮助都将不胜感激

艾伦

我找不到如何复制一个文件 迭代器

最近的是,但正如@J.F.Sebastian所建议的,简单地列出它的
列表是最好的,正如itertools.tee的文档所解释的:

此itertool可能需要大量的 辅助存储器(取决于使用方式 需要更新许多临时数据 存储的)。通常,如果一个迭代器 使用之前的大部分或所有数据 另一个迭代器启动,速度更快 使用
list()
代替
tee()


您只需打开文件一次:

import csv

f = open('myFile.csv', 'rb')

countrdr = csv.DictReader(f)
totalrows = 0
for row in countrdr:
  totalrows += 1

f.seek(0)  # You may not have to do this, I didn't check to see if DictReader did

myreader = csv.DictReader(f)
for row in myreader:
  do_work
不管你做什么,你都必须做两次传递(如果你的记录是固定长度的——这是不可能的——你可以得到文件大小并进行除法,但假设情况并非如此)。再次打开文件确实不需要花费太多,但可以避免,如图所示。仅仅为了使用
len()
而转换为列表可能会浪费大量内存,而且不会更快

注意:“Pythonic”方法是使用
枚举
而不是
+=
,但是
解包元组
操作码非常昂贵,这使得
枚举
比增加本地值慢。这就是说,这可能是一个不必要的微优化,您可能应该避免


更多说明:如果你真的只想生成某种进度指标,它不一定要基于记录。您可以对循环中的file对象执行
tell()
,只需报告所处理数据的百分比。这会有点不均匀,但在任何足以保证进度条的文件上,记录长度的偏差都会在噪音中丢失。

如答案中所述,您可以通过将读取器的长度转换为列表来获得行数。然而,这将对RAM消耗产生影响,并且您将失去读卡器(它是一个生成器)的好处

我认为最好的解决方案是打开文件2次:

  • 计算行数:
  • total_rows=sum(1表示u处于打开状态('myFile.csv'))#-1,如果要从计数中删除标题
    
    注意:我没有使用
    .readlines()
    来避免加载内存中的所有行

  • 逐行迭代

  • 根据您的代码片段,您将有如下内容:

    导入csv
    totalrows=sum(1表示打开中的uu('myFile.csv'))
    myreader=csv.DictReader(打开('myFile.csv'))
    对于i,u在枚举中(myreader,start=1):
    打印(“行%d/%d”%(i,总计行))
    
    注意:
    enumerate
    中的
    start=1
    表示i的第一个值。默认值为0,如果保留此默认值,则必须在打印语句中使用
    i+1


    如果您确实不想打开文件两次,可以使用回答中提到的
    seek

    导入csv
    f=打开('myFile.csv'))
    总计行数=总和(1表示f中的行数)
    f、 搜索(0)
    myreader=csv.DictReader(f)
    对于i,u在枚举中(myreader,start=1):
    打印(“行%d/%d”%(i,总计行))
    
    无论使用哪种方法,您都会有潜在的巨大资源消耗。谢谢Alex-列出它。很好的解决方案-我对迭代器的概念非常陌生,所以直到现在我才真正了解enumerate()。注意。请注意这里的数据集大小。将你的阅读器变成一个列表可能会占用大量内存。这会将所有数据加载到内存中,计算行数-1是非常好的解决方案尼克-谢谢你的回复。看起来我避免重新打开文件的做法不值得花费额外的代码(在这种情况下,可读性高于性能)。感谢您提供有关enumerate()速度的提示。Tell()对我来说也是一个新概念,我将进一步研究它。这是唯一的问题。。如果您使用的是steam,该怎么办。@尼克:世界上没有魔法-这不是问题,只是事实。DictReader在您迭代之后不会返回开始,但是如果您没有指定标题,它会使用第一行作为标题,您需要在使用
    seek(0)
    countrdr.next()
    import csv
    
    f = open('myFile.csv', 'rb')
    
    countrdr = csv.DictReader(f)
    totalrows = 0
    for row in countrdr:
      totalrows += 1
    
    f.seek(0)  # You may not have to do this, I didn't check to see if DictReader did
    
    myreader = csv.DictReader(f)
    for row in myreader:
      do_work