Skip to main content

CP03CSV文件合并

阅读:-


在编制报表的时候,我们常常需要将多个文件合并为一个文件,在转入后续的环节进行处理,这样可以简化相关报表的处理效率。避免在处理过程中,反复的打开关闭文件。所以如何将多个CSV文件合并为一个文件,也是报表处理过 程中,非常重要的一个技能。

3 文件读写-多CSV文件合并

3.1 问题背景分析

随着银行业和金融业的蓬勃发展。但是从金融云平台上导出的所产生的数据状况数以亿计字节的信息。大量的数据被获取、交流、集聚、存储和分析,从其拥有的数据规模、数据的复杂类型来看,处理起来会带来各种问题,以及对庞大的数据解析所消耗的时间,都会造成现场处理不便,学会使用工具读写文件是我们学习的第一步。

1587274688365

3.1.1 输入数据分析 (I)

为了简化问题的分析,我们假设获取到了一个清单。分别是

QLR2019020710-001.csv

QLR2019020710-002.csv

QLR2019020710-003.csv

文件数据格式如下:

1587274715627

3.1.2 处理过程(P)

  1. 用户需要在计算本地读取001.csv文件内的数据。

    2.将csv文件中的数据转化到计算机内存系统,在控制台查看输出结果,并截图保存。

  2. 依次读取002.csv与003.csv,将三个文件合并成一个summary.csv

3.1.3输出数据(O)

由于这个用例比较简单,所以我们就不阐述相关的处理过程,处理的目标是将三个文件合并为一个文件。合并的文件命名为:

summary.csv

输出文件的路径在D: 盘的根目录下。

3.2 用例约束

1.要求使用os组件进行文件读写。

2.要求使用os组件遍历目录,选中目录中所有csv文件,进行选择性读取。

3.要求至少使用一次上下文选择器。

4.要求就如何除去表头进行方案探讨。

3.3 设计方案简介

3.3.1 Os方案

3.3.1.1 设计要点

1、将多个文件进行合并,考虑标题的过滤。

3.3.1.2 调用关系

1587274875487

3.3.1.3 流转换

  1. filelist

1587274932865

  1. header_txt

1587274971557

  1. f_txt

1587275013722

4.写入csv文件

1587275057441

3.3.2 Csv方案

3.3.2.1 调用关系:

1587275101552

3.3.2.2 流穿越

  1. csvwriter

1587275180244

这里csv.writer 是内存中的一个实例对象,并不能直接进行打印操作。

  1. csv_rows = csv_reader(filename)

包含文件中所有信息,第一行为头部

代码如下:

1587275323572

1587275349559

3.写入时,第一行为头部,第二行开始即为内容。

4.写入csv文件

1587275396110

3.4 OS 设计方案详解

3.4.1 OS方案领域对象模型

1587276035581

   图 3-2 基于OS方案的领域对象模型

从上图可见,以上是基于OS方案的领域对象模型。其中主要的逻辑说明如下:

1.打开一个输出文件的句柄Out,这个文件句柄代表一个可以进行文件对象操作的对象。

2.根据待处理的filelist,打开一个文件,生成一个输入文件句柄header,这个文件句柄也代表了一个可以进行文件对象操作的对象。

  1. 生成CSV的表头数据

3.1 调用句柄header的readline()方法读取文件对象的第一行,将返回值(字符串)赋值给一个变量headertext;

3.2 利用句柄out的write()方法,将表头数据输出到文件中。

3.3 关闭句柄header。

4.根据filelist列表,迭代输出csv的行数据。

4.1 选取第一个文件。

4.2 针对这个文件打开一个句柄f;

4.3 调用句柄f的readline()方法读取文件对象的第一行,这是一个空操作,目的是跳过csv文件的表头。

4.4 调用句柄f的的read()方法,将CSV文件的行数据读取到一个字符串f_txt中。

4.5 关闭句柄句柄f。

4.6 继续进行迭代处理,直到全部的文件都处理完毕。

5.全部文件处理完毕以后,CSV文件合并成功,关闭文件句柄out。

以上就是核心的领域对象的协作过程,也是一个经典的流转换处理方法。

3.4.2 关键技能点

OS文件读取/合并enumerate()操作列举;枚举实现迭代处理的机制
read()方法的返回值说明read()方法的对象说明read()方法的对象
filelist[1][1]如何从list中提取str如何从list中提取str
将CSV文件转换为list格式转换
基于列表生成式输出列表生成式

3.4.3 enumerate()操作

3.4.3.1 应用目的

由题意得,我们需要获取一个文件的序号,通常的方法是自定义一个计时器,程序每运行一次数量加一,但使用enumerate后一切就变得更为简单,enumerate给可迭代对象增加序号

3.4.3.2 语法说明

语法

以下是 enumerate() 方法的语法:

enumerate(sequence, [start=0])

参数

  • sequence — 一个序列、迭代器或其他支持迭代对象。

  • start — 下标起始位置。

返回值

返回 enumerate(枚举) 对象。

3.4.3.3 Case举例

实例1:

1587276308020

实例2:

1587276333319

1587276351146

综合上面的分析,我们发现,使用enumerate() 的函数以后,可以简化循环的处理过程,极大的简化相关的遍历操作的方便性。

3.4.3.4 应用注意点

请结合题意进行使用,并非所有循环都需要添加enumerate

3.4.4 read()方法的返回值

3.4.4.1 应用目的

Python原生读取文件的基本方法,流操作的第一步read读文件

3.4.4.2 语法说明

概述

read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有。

语法

read() 方法语法如下:

fileObject.read(); 

参数

  • size — 从文件中读取的字节数。

返回值

返回从字符串中读取的字节。

3.4.4.3 Case举例

循环读取文件的内容:

1587283789740

1.4.4.4 应用注意点

1、 read有三种模式,根据具体应用场景选择使用

2、 read有内置方式选择,如 r rw a等需要理解

3、 read有编码格式需要考虑

3.4.5 filelist[1][1]

3.4.5.1 应用目的

list作为一个容器,用于存放数据,从这个容器中拿值,便是流转换过程中的关键一步了

3.4.5.2 语法说明

List[索引为0到list长度]

3.4.5.3 Case举例

filelist= [(0, ‘G-QLR2019020710-001.xml’), (1, ‘G-QLR2019020710-002.xml’), (2, ‘G-QLR2019020710-003.xml’), (3, ‘T-QLR2019020710-001.xml’), (4, ‘T-QLR2019020710-002.xml’), (5, ‘T-QLR2019020710-003.xml’)]

1587283928972

1587283955311

3.4.5.4 应用注意点

通过list的索引取值是基本方案,但不是最好方案,能否通过id定位到数值,便是我们后续要学习的内容了。

3.4.6 将CSV文件转换为list

3.4.6.1 应用目的

将本地csv文件中的数据存储在内存list中

3.4.6.2 Case举例

1、 读取csv为str

f = open(input +"/"+  filelist[1][1], 'r')

f_txt = f.read()

1587284077007

2、 切割字符串

f_txt.split(",")

['tac-003', '201802071006 ', 'QLR', 'op01', 'cu02', '李四', 'Withdrawal', '2000\ntac-004', '201802071008 ', 'QLR', 'op01', 'cu02', '李四', 'Withdrawal', '3000\n']

3.4.6.3 应用注意点

数据流的转换,根据实际应用场景进行选择.

3.4.8 基于列表生成式输出

3.4.8.1 应用目的

1、 列表解析式运行效率最快,生成器表达式最省空间,速度也还可以。

2、 一次性返回整个列表

3、 简化代码,列表生成式,一行代码可以拆分为多行

3.4.8.2 语法说明

[I for I in 可迭代对象]

3.4.8.3 Case举例

1587284224541

1587284251665

3.4.8.4 应用注意点

需要深度学习列表生成式的语法结构,学会使用列表生成式

3.5 CSV设计方案详解

3.5.1 函数调用关系

![1587284294145](./1587284294145.png)

   图 3-3 基于CSV组件的合并处理

从上图可见,借助CSV组件,提供了更好的封装性,两个核心的函数功能,简述如下:

1.merge():实现多个CSV文件的合并功能,其中输入是1个列表,其中包含了待合并的文件清单,输出是合并文件的绝对路径, 也就是合并以后的文件对象。

2.CSV_reader(filename): 是一个原子csv文件的装载器,实现将CSV文件加载在内存中。

3.5.2 CSV方案的领域对象模型

1587284321944

图3-4 基于CSV方案的合并

从上图可见,相关的方案中核心的函数为merge(filelist,dist)

相关核心的领域对象说明如下

1,写文件句柄: 在这个方案中,有两个写文件句柄,其中distfile是一个OS级别的句柄,而csvwriter是进一步基于CSV组件进行封装的APP级别的句柄,经过封装以后,写写操作很方便。

2、CSV_rows:这是一个列表,他是将CSV文件转换为一个列表,其中包含的元素的数量=表头+数据行数。

3、header[] 这也是一个列表,负责记录表头的信息结构,并方便做一些合规性的判断。

3.5.2.1 函数csv_reader(filename)

1587284370635

   图3-5 将CSV文件转换为列表

从上图可见,为了方便处理,封装了一个函数实现相关的将CSV文件转换为列表的功能,这样后续的处理就比较简单,还可以实现一些比较复杂的逻辑。

3.5.2.2 表头判断

当我们合并csv文件的时候,有可能多个文件的表头信息结构并不一致,所以在这里增加检查的判断。这里用到了两个元素(list格式)的比较计算。

1587284396541

3.5.3 关键技能点

1587284442746

3.5.4 文件尺寸大小识别

3.5.4.1 应用目的

识别文件大小,记录文件信息

3.5.4.2 语法说明

fsize = os.path.getsize(filename)

3.5.4.3 Case举例

1587284525483

3.5.4.4 应用注意点

Os组件,用于识别文件大小。

3.5.5 基于csv组件操作list

3.5.5.1 应用目的

使用python原生语法读取文件固然是能够完成的,但每次的流转换都是从零开始构建,寻求一套归一化便利的解决方案,所以使用到了组建csv,专业处理csv文件格式转换。

3.5.5.2 语法说明

spamreader = csv.reader(csvfile)
csvwriter = csv.writer(distfile)
csvwriter.writerow(header)

1.5.5.3 Case举例

读文件:

读取csv时需要使用reader,并传如一个文件对象,而且reader返回的是一个可迭代的对象,需要使用for循环遍历,代码如下:

 
import csv

with open('test.csv')as f:

    f_csv = csv.reader(f)

    for row in f_csv:

    print(row)

运行结果:

1587284768239

在上面,row是一个列表,如果想要查看固定的某列,则需要加上下标,例如我想要查看name,那么只需要改为row[1]

import csv

with open('test.csv')as f:

    f_csv = csv.reader(f)

    for row in f_csv:

        print(row[1])

1587284795659

写文件

import csv

 headers = ['class','name','sex','height','year']

 rows = [

        [1,'xiaoming','male',168,23],

        [1,'xiaohong','female',162,22],

        [2,'xiaozhang','female',163,21],

        [2,'xiaoli','male',158,21]

    ]

 

with open('test.csv','w')as f:

    f_csv = csv.writer(f)

    f_csv.writerow(headers)

    f_csv.writerows(rows)

1587284823667

3.5.5.4 应用注意点

每个组件都有自己固定的语法与应用场景,需要自己记忆理解,根据实际问题分析使用。

3.6 总结

在本方案中,应用了两种合并的方案。

1,基于OS原生组件的方式,理解比较直观,但是添加一些增强功能比较玛法。

2,使用csv组件的方式,可以封装一些复杂的功能,扩展性比较好,但是在读写操作上,均需要在OS层之上,增加一层APP层。

分享到微博
Starter
MicroServ
Tutorials
Report
Blog