【问题标题】:Merge csv files, add original file name to each row in output file合并 csv 文件,将原始文件名添加到输出文件中的每一行
【发布时间】:2021-05-04 19:12:18
【问题描述】:

我在一个文件夹中有多个 csv 文件具有相同的数据结构,

0.00;1.05;10.5
0.01;2.05;15.5
0.02;3.05;20.5
...

我想将所有 csv 文件合并到 1 个摘要文件中,并根据原始数据源在每一行添加一个带有文件名的列。

0.00;1.05;10.5;csv1.csv
0.01;2.05;15.5;csv1.csv
0.02;3.05;20.5;csv1.csv
0.00;5.05;0.05;csv2.csv
0.01;6.05;1.05;csv2.csv
0.02;7.05;2.05;csv2.csv
...

我设法合并文件,但找不到添加文件名的方法。

files = []
for file in os.listdir(folder):
    if file.endswith('.csv'):
        files.append(file)
with open('results.csv', 'w', newline='') as fw:
        cw = csv.writer(fw)
        for file in files:
            with open(file, newline='') as f:
                cr = csv.reader(islice(f,13,None)
                cw.writerows(cr)

由于内存限制,我不想使用 pandas concat。 谢谢你。

【问题讨论】:

    标签: python csv merge


    【解决方案1】:

    您不需要解析输入的 csv 文件,只需在每一行附加一个分隔符,然后是当前文件名。您可以使用fileinput 模块:

    import fileinput
    from pathlib import Path
    
    folder = '.'        # set accordingly, assume current directory
    path = Path(folder)
    with fileinput.input(files=path.glob('*.csv')) as f, open('results.csv', 'w') as outfile:
        for line in f:
            print(';'.join([line.rstrip('\n'), fileinput.filename().name()]), file=outfile)
    

    关于你的代码,你可以这样修复它:

    import os
    import csv
    
    folder = '.'
    files = []
    for file in os.listdir(folder):
        if file.endswith('.csv'):
            files.append(file)
    
    with open('results.csv', 'w', newline='') as fw:
            cw = csv.writer(fw, delimiter=';')
            for file in files:
                with open(file, newline='') as f:
                    for row in csv.reader(f, delimiter=';'):
                        row.append(file)
                        cw.writerow(row)
    

    这里delimiter 参数设置为分号,因为默认分隔符是逗号,并且您的文件使用;。这将修复输入 csv 文件的正确解析,并将; 用于输出文件。然后通过读取每一行并将文件名附加到行列表来处理每个输入文件。最后将新行写入输出 CSV 文件。

    【讨论】:

      【解决方案2】:

      您可以使用ospandas

      import os
      import pandas as pd
      
      basedir = <path of your base folder>
      
      all_dfs = []
      for filename in filter(lambda f: os.path.splitext(f)[1] == '.csv', next(os.walk(basedir))[2]):
          curr_df = pd.read_csv(os.path.join(basedir, filename), sep=';', header=None)
          curr_df['filename'] = filename
          all_dfs.append(curr_df)
      
      pd.concat(all_dfs, axis=0).to_csv('merged_cvs.csv', sep=';', header=False, index=False)
      

      或者,如果您只喜欢一行:

      pd.concat([pd.concat((df, pd.DataFrame([f for _ in range(len(df))])), axis=1) for f, df in
          ((filename, pd.read_csv(os.path.join(basedir, filename), sep=';', header=None))
          for filename in filter(lambda f: os.path.splitext(f)[1] == '.csv', next(os.walk(basedir))[2]))
      ]).to_csv('merged_cvs.csv', sep=';', header=False, index=False)
      

      【讨论】:

        【解决方案3】:
        files = []
        for file in os.listdir(folder):
            if file.endswith('.csv'):
                files.append(file)
        with open('results.csv', 'w', newline='') as fw:
            cw = csv.writer(fw)
            for file in files:
                with open(file, newline='') as f:
                    fw.write(f"{file}\n")  # just write the filename before the content :)
                    cr = csv.reader(islice(f,13,None)
                    cw.writerows(cr)
        

        【讨论】:

        • 您好,谢谢。但我得到了错误:TypeError: write() argument must be str, not bytes
        猜你喜欢
        • 1970-01-01
        • 2014-02-26
        • 2019-07-21
        • 2020-11-14
        • 2017-08-20
        • 1970-01-01
        • 2013-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多