4

我正在使用谷歌云存储客户端库。

我正在尝试使用以下代码打开和处理 CSV 文件(已上传到存储桶):

filename = '/<my_bucket/data.csv'
with gcs.open(filename, 'r') as gcs_file:
    csv_reader = csv.reader(gcs_file, delimiter=',', quotechar='"')

我收到错误“参数 1 必须是迭代器”以响应 csv.reader 的第一个参数(即 gcs_file)。显然 gcs_file 不支持迭代器 .next 方法。

关于如何进行的任何想法?我需要包装 gcs_file 并在其上创建一个迭代器还是有更简单的方法?

4

2 回答 2

3

我认为最好有自己的为 csv.reader 设计的包装器/迭代器。如果 gcs_file 要支持Iterator协议,则不清楚 next() 应该返回什么以始终适应其使用者。

根据 csv reader doc,它

返回一个读取器对象,它将遍历给定 csvfile 中的行。csvfile 可以是任何支持迭代器协议并在每次调用其 next() 方法时返回一个字符串的对象——文件对象和列表对象都适用。如果 csvfile 是文件对象,则必须在不同的平台上使用 'b' 标志打开它。

它需要来自底层文件的一大块原始字节,不一定是一行。您可以拥有这样的包装器(未经测试):

class CsvIterator(object)
  def __init__(self, gcs_file, chunk_size):
     self.gcs_file = gcs_file
     self.chunk_size = chunk_size
  def __iter__(self):
     return self
  def next(self):
     result = self.gcs_file.read(size=self.chunk_size)
     if not result:
        raise StopIteration()
     return result

关键是一次读取一个块,这样当你有一个大文件时,你不会炸毁内存或遇到 urlfetch 超时。

或者更简单。要使用内置的iter :

csv.reader(iter(gcs_file.readline, ''))
于 2013-07-24T19:58:45.763 回答
1

尝试这个:

from StringIO import StringIO
filename = '/<my_bucket/data.csv'
with gcs.open(filename, 'r') as gcs_file:
    csv_reader = csv.reader(StringIO(gcs_file.read()), delimiter=',',
                            quotechar='"')

但这并不理想。我已经提交了一项功能请求,要求 GCS 文件支持迭代。

于 2013-07-24T18:26:33.953 回答