6.4 KiB
6.4 KiB
CSVData 类技术文档
CSVData 是一个用于读取和处理 CSV 文件的 Python 类,提供了两种读取模式:一次性加载全部数据(read())和逐行迭代处理(iterRead())。该类支持自定义字段名、跳过标题行和数据起始行,适用于灵活解析各种格式的 CSV 数据。
📦 模块依赖
import csv
使用标准库中的
csv模块进行 CSV 文件解析。
🔧 类定义
class CSVData(csvfile, names=None, headline=0, dataline=1)
参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
csvfile |
str | 必填 | CSV 文件路径 |
names |
list 或 None | None |
自定义字段名称列表。若提供,则忽略文件中的标题行 |
headline |
int | 0 |
标题行所在的行号(从 0 开始),仅在 names 为 None 时使用 |
dataline |
int | 1 |
实际数据开始的行号(从 0 开始) |
📚 方法说明
1. __init__(self, csvfile, names=None, headline=0, dataline=1)
初始化 CSVData 实例,设置文件路径与解析参数。
2. read(self) -> list[dict]
以列表形式返回所有记录,每条记录是一个字典(键为字段名,值为对应列值)。
返回值:
list[dict]: 包含所有数据记录的列表,例如:[ {'st_date': '2024-01-01', 'open_price': '100', ...}, {'st_date': '2024-01-02', 'open_price': '102', ...}, ... ]
工作流程:
- 打开 CSV 文件(二进制模式
'rb'⚠️ 存在潜在问题,请见下方【⚠️ 注意事项】) - 创建
csv.reader对象 - 若未指定
names,则读取第headline行作为字段名 - 从第
dataline行开始逐行构建字典记录并添加到结果列表中 - 关闭文件并返回数据
✅ 适合小到中等规模的数据集。
3. iterRead(self)
以流式方式逐行读取 CSV 文件,并触发事件回调函数。适用于大数据文件,避免内存溢出。
回调机制:
onBegin(): 在开始读取前调用(当前实现为空)onRecord(rec): 每处理一行有效数据时调用onFinish(): 成功完成读取后调用
异常处理:
- 使用
try-except捕获异常,确保文件关闭 - 出现错误时重新抛出异常(但变量作用域有误,请见【⚠️ Bug 提示】)
✅ 推荐用于大型 CSV 文件处理。
4. onBegin(self)
钩子方法,在迭代读取开始前被调用。默认为空实现,可由子类重写。
当前代码中调用了
self.onBegin(),但该方法未定义 —— 应为onReadBegin?请见下方 Bug 分析。
5. onRecord(self, rec)
每读取一条有效记录时调用此方法。
参数:
rec(dict): 当前行数据,形如{字段名: 值}
默认行为:
打印当前记录(print(rec))
可继承此类并重写该方法以实现自定义逻辑(如入库、计算等)。
6. onFinish(self)
所有数据读取完成后调用。
默认行为:
打印 "onFinish() called"
可用于资源清理或结束通知。
🖥️ 示例用法
if __name__ == '__main__':
import sys
cd = CSVData(
sys.argv[1],
names=['st_date','open_price','max_price','min_price','close_price','volume','adj_price']
)
cd.iterRead()
说明:
- 从命令行传入 CSV 文件路径
- 使用自定义字段名,不依赖文件头部
- 调用
iterRead()流式输出每一行数据
⚠️ 注意事项与改进建议
❗Bug 与潜在问题
| 问题 | 描述 | 建议修复 |
|---|---|---|
1. onBegin() 调用错误 |
代码中调用 self.onBegin(),但实际定义的是 onReadBegin(),会导致 AttributeError |
将 onReadBegin 改名为 onBegin,或修正调用 |
| 2. 异常捕获语法错误 | except exception as e: 中 exception 应为 Exception(首字母大写) |
改为 except Exception as e: |
| 3. 文件打开模式冲突 | read() 方法使用 'rb' 二进制模式打开文件,但 csv.reader 需要文本模式 |
改为 'r' 并指定编码(如 'utf-8') |
4. fd.close() 变量作用域错误 |
在 except 块中调用 fd.close(),但 fd 是实例属性应写作 self.fd |
改为 self.fd.close() |
| 5. 缺少编码设置 | 未指定字符编码,可能导致中文乱码 | 添加 encoding='utf-8' 参数 |
✅ 推荐修改后的 iterRead() 示例:
def iterRead(self):
self.fd = open(self.csvfile, 'r', encoding='utf-8')
try:
reader = csv.reader(self.fd)
fields = None
if self.names is not None:
fields = self.names
lno = 0
self.onBegin() # 确保方法存在
for l in reader:
if fields is None and lno == self.headline:
fields = [f for f in l]
if lno >= self.dataline:
rec = {}
for i in range(len(fields)):
rec[fields[i]] = l[i]
self.onRecord(rec)
lno += 1
self.fd.close()
self.onFinish()
except Exception as e:
self.fd.close()
raise e
🧩 继承与扩展建议
可通过继承 CSVData 类来实现更复杂的功能:
class MyCSVProcessor(CSVData):
def onBegin(self):
print("开始处理数据...")
def onRecord(self, rec):
# 示例:过滤价格大于 100 的记录
if float(rec['close_price']) > 100:
print("高价值记录:", rec)
def onFinish(self):
print("数据处理完毕!")
📎 总结
| 特性 | 支持情况 |
|---|---|
| 自定义字段名 | ✅ |
| 跳过标题行 | ✅ |
| 指定数据起始行 | ✅ |
| 全量读取 | ✅ (read) |
| 流式读取 | ✅ (iterRead) |
| 可扩展性 | ✅(支持回调钩子) |
| 错误处理 | ⚠️ 存在缺陷,需修复 |
| 编码支持 | ❌ 缺失,建议增加 |
📌 版本建议(改进方向)
- 增加
encoding参数,默认'utf-8' - 修复异常捕获与方法命名
- 使用上下文管理器 (
with open(...)) 替代手动关闭文件 - 添加类型注解提升可读性
- 支持分隔符参数(如 tab、分号等)
📘 结论:CSVData 是一个结构清晰、易于扩展的 CSV 处理类,稍作修正后可用于生产环境。