如何在 "rb" 模式下使用 csv 模块读取 csv 文件的 headers?

How to read the headers of a csv file using csv module in "rb" mode?

我目前正在 "rb" 模式下读取 csv 文件并将文件上传到 s3 存储桶。

with open(csv_file, 'rb') as DATA:
    s3_put_response = requests.put(s3_presigned_url,data=DATA,headers=headers)

所有这些都工作正常,但现在我必须在进行 put 调用之前验证 csv 文件中的 headers。

当我在下面尝试 运行 时,出现错误。

with open(csv_file, 'rb') as DATA:
       csvreader = csv.reader(file)
       columns = next(csvreader)
       # run-some-validations
       s3_put_response = requests.put(s3_presigned_url,data=DATA,headers=headers)

这抛出

_csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)

作为解决方法,我创建了一个新函数,它以 "r" 模式打开文件并对 csv headers 进行验证,这工作正常。

def check_csv_headers():
    with open(csv_file, 'r') as file:
        csvreader = csv.reader(file)
        columns = next(csvreader)

我不想读取同一个文件两次。一次用于 header 验证,一次用于上传到 s3。如果我在 "r" 模式下上传,上传部分也不起作用。

有什么方法可以在 "rb" 模式下只读取一次文件来实现这一点?我必须使用 csv 模块而不是 pandas 库来完成这项工作。

做你想做的事是可能的,但效率不高。简单地打开一个文件并不那么昂贵。 CSV reader 一次只读取一行,而不是整个文件。

要做你想做的事你必须:

  1. 以字节形式读取第一行
  2. 解码成字符串(使用正确的编码)
  3. 将其转换为字符串列表
  4. csv.reader 解析它,最后
  5. 定位到流的开头。

否则,您最终将只上传没有 headers 的数据:

with open(csv_file, 'rb') as DATA:
   header=file.readline()
   lines=[header.decode()]
   csvreader = csv.reader(lines)
   columns = next(csvreader)
   // run-some-validations
   DATA.seek(0)

   s3_put_response = requests.put(s3_presigned_url,data=DATA,headers=headers)

以文本形式打开文件不仅更简单,还允许您将验证逻辑与上传代码分开。

要确保一次只读取一行,您可以使用 buffering=1

def check_csv_headers():
    with open(csv_file, 'r', buffering=1) as file:
        csvreader = csv.reader(file)
        columns = next(csvreader)
        // run-some-validations

    with open(csv_data, 'rb') as DATA:
        s3_put_response = requests.put(s3_presigned_url,data=DATA,headers=headers)

def check_csv_headers():
    with open(csv_file, 'r', buffering=1) as file:
        csvreader = csv.reader(file)
        columns = next(csvreader)
        // run-some-validations
        //If successful
        return True

def upload_csv(filePath):
    if check_csv_headers(filePath) :    
        with open(csv_data, 'rb') as DATA:
            s3_put_response = requests.put(s3_presigned_url,data=DATA,headers=headers)