簡體   English   中英

根據內容讀取一個 csv 文件並寫入不同的多個 csv 文件

[英]Read from one csv file and write to different multiple csv files depending on content

我有一個很大的 csv 文件,我正在閱讀它。根據 column1 中字符串的前兩個值,我想將內容 output 到不同的 csv 文件。

文件可能如下所示:

Column1;Column2
01;BE
02;ED
12;FD
14;DS
03;ED
04;DF

我的代碼如下:

import csv
output_path=r'C:\myfolder\large_file.csv'

with open(os.path.join(os.path.dirname(output_path),"column1_01.csv"), "w", encoding="utf-8", newline='') as \
out_01, open(os.path.join(os.path.dirname(output_path),"column1_02.csv"), "w", encoding="utf-8", newline='') as \
out_02, open(os.path.join(os.path.dirname(output_path),"column1_03.csv"), "w", encoding="utf-8", newline='') as \
out_03, open(os.path.join(os.path.dirname(output_path),"column1_04.csv"), "w", encoding="utf-8", newline='') as \
out_04:
    
    cw01 = csv.writer(out_01, delimiter=";", quoting=csv.QUOTE_MINIMAL)
    cw02 = csv.writer(out_02, delimiter=";", quoting=csv.QUOTE_MINIMAL)
    cw03 = csv.writer(out_03, delimiter=";", quoting=csv.QUOTE_MINIMAL)
    cw04 = csv.writer(out_04, delimiter=";", quoting=csv.QUOTE_MINIMAL)

    with open(output_path, encoding="utf-8") as in_f:
        cr = csv.reader(in_f, delimiter=";")
        cw01.writerow(next(cr))
        cw02.writerow(next(cr))
        cw03.writerow(next(cr))
        cw04.writerow(next(cr))

        for line in cr:
            if (line[0][:2] =="01"): cw01.writerow(line)  
            if (line[0][:2] =="02"): cw02.writerow(line)  
            if (line[0][:2] =="03"): cw03.writerow(line)  
            if (line[0][:2] =="04"): cw04.writerow(line)  

我現在的問題是,當我添加下一行時,“05”的 output 我得到一個錯誤停止迭代(我用示例數據檢查了它並且其中沒有太多數據行,所以我想它必須做一些事情它)。 此外,主要問題是在檢查文件時我發現它不起作用。 它沒有將記錄正確輸出到正確的文件中。 我的錯誤在哪里?

我認為問題可能出在所有 next(cr) 上。 我想要做的只是使用原始大 csv 中的 header 並為每個 csv 提供它。header 是相同的。 我需要最后帶有 header 的所有文件。

我需要一個純 csv 解決方案。 沒有其他包裹。

我想在我的代碼中找到准確的錯誤。 為什么這不起作用,錯誤在哪里? 我不希望任何進一步的更改引入異常處理,如 try、def 等函數或任何其他函數。 我不需要通用解決方案。 我想在我的代碼中找到具體的錯誤。

原來的大文件有很多列,所以 header 相當長。 因此,我想要一個無需手動輸入所有列即可將其添加到 header 的解決方案。

Python 內置 function next通過調用其__next__()方法從迭代器中檢索下一項。 因此,迭代器向前移動到下一個元素。 因此,您多次致電next以獲取 header。

[...]
    with open(output_path, 'r', encoding="utf-8") as in_f:
        cr = csv.reader(in_f, delimiter=";")
        header = next(cr)
        cw01.writerow(header)
        cw02.writerow(header)
        cw03.writerow(header)
        cw04.writerow(header)

        for line in cr:
[...]

希望有所幫助。

當你這樣做時會發生什么? 我打亂了你的代碼以使其通用,這樣你就可以給出任何cols列表,它會為每個 col 生成 1 個 output 文件,並在 csv 作者的字典中查找 col。

import csv
output_path = r'C:\myfolder\large_file.csv'


def get_fhandle(col_name):
  return open(
    os.path.join(os.path.dirname(output_path), f"column1_{col_name}.csv"),
    "w", encoding="utf-8", newline=''
  )

cols = ["01", "02", "03", "04", "05"]
files = {col: get_fhandle(col) for col in cols}
try:
  writers = {
    col: csv.writer(file, delimiter=";", quoting=csv.QUOTE_MINIMAL)
    for col, file in files.items()
  }
  with open(output_path, encoding="utf-8") as in_f:
    cr = csv.reader(in_f, delimiter=";")
    header = next(cr)
    for writer in writers.values():
      writer.writerow(header)
    for line in cr:
      col = line[0][:2]
      if col not in writers:
        raise ValueError(
          f"'{col}' is not a known column. Should be: {cols.join(', ')}"
        )
      writers[col].writerow(line)
finally:
  for file in files.values():
    file.close()

contextlib.ExitStack()的使用允許我們徹底清理事情,特別是如果我們設置一個小字典來 map 我們輸入 map 中的哪些鍵到我們想要寫入的 output 文件。

import contextlib
import csv

files_out = {
    "01": "column1_01.csv",
    "02": "column1_02.csv",
    "03": "column1_03.csv",
    "04": "column1_04.csv",
}

with contextlib.ExitStack() as stack:
    ## ---------------------
    ## Set up a bunch of csv writers
    ## ---------------------
    writers = {
        key: csv.writer(stack.enter_context(open(value, "w", newline="")))
        for key, value
        in files_out.items()
    }
    ## ---------------------

    file_in = stack.enter_context(open("small.csv"))
    rows = csv.reader(file_in, delimiter=";")

    ## ---------------------
    ## write a header to each output file
    ## ---------------------
    headers = next(rows)
    for writer in writers.values():
        writer.writerow(headers)
    ## ---------------------

    ## ---------------------
    ## write rows to the appropriate file
    ## ---------------------
    for row in rows:
        key = row[0]
        if not key in writers:
            print(f"no file defined for key {key}")
            continue
        writers[key].writerow(row)
    ## ---------------------

要回答您的代碼為何當前無法運行的具體問題,讓我們看一下:

with open(output_path, encoding="utf-8") as in_f:
    cr = csv.reader(in_f, delimiter=";")
    cw01.writerow(next(cr))
    cw02.writerow(next(cr))
    cw03.writerow(next(cr))
    cw04.writerow(next(cr))

    for line in cr:
        if (line[0][:2] =="01"): cw01.writerow(line)  
        if (line[0][:2] =="02"): cw02.writerow(line)  
        if (line[0][:2] =="03"): cw03.writerow(line)  
        if (line[0][:2] =="04"): cw04.writerow(line)  

這里:

cw01.writerow(next(cr))

本質上是將輸入文件的第一行(標題)寫入第一個 output 文件。 然后我們重復此操作,將連續的輸入行寫入輸出。

在將前 4 行輸入寫入四個輸出中的每一行后,我們然后讀取輸入文件中的剩余行(示例中的最后兩行)並將它們適當地寫入文件 3 和 4

因此,您的具體解決方案是使用next()從輸入文件中獲取 header,然后將其寫入每個 output 文件:

with open(output_path, encoding="utf-8") as in_f:
    cr = csv.reader(in_f, delimiter=";")
    headers = next(cr)

    cw01.writerow(headers)
    cw02.writerow(headers)
    cw03.writerow(headers)
    cw04.writerow(headers)

    for line in cr:
        if (line[0][:2] =="01"): cw01.writerow(line)  
        if (line[0][:2] =="02"): cw02.writerow(line)  
        if (line[0][:2] =="03"): cw03.writerow(line)  
        if (line[0][:2] =="04"): cw04.writerow(line)  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM