第三章 数据读取与存储:从文件到数据库的实战之路
大家好,我是你们的老朋友。今天我们来聊聊数据读取与存储这个话题。说实话,这可能是整个课程里最「接地气」的一章了。为什么?因为不管你算法写得再漂亮,数据读不进来、存不下去,一切都是白搭。
我在做仪器开发的头几年,就吃过不少这方面的亏。有一次现场调试,仪器采集了一整天的数据,结果因为存储格式选错了,最后数据全废了。从那以后,我对数据读写这块就格外上心。
好,咱们直接进入正题。
3.1 CSV与Excel文件读写:最常用的数据交换格式
先说CSV。这玩意儿简单,说白了就是用逗号分隔的文本文件。几乎所有仪器软件都支持导出CSV格式。我个人的习惯是:能用CSV就用CSV,因为它跨平台、跨语言,而且人类可读。
Python里读写CSV,我推荐用pandas。为什么?因为快,而且代码少。
import pandas as pd
# 读取CSV
df = pd.read_csv('instrument_data.csv')
print(df.head())
# 写入CSV
df.to_csv('processed_data.csv', index=False)
嗯,就这么简单。但这里有个坑——编码问题。我曾经在项目中遇到过一个CSV文件,怎么读都是乱码。后来发现是编码格式不对。中文数据经常用GBK,而pandas默认是UTF-8。
pd.read_csv('file.csv', encoding='gbk')。如果不确定编码,可以用chardet库先检测一下。
再说Excel。Excel文件比CSV复杂,因为它支持多工作表、公式、格式等。但好在pandas也支持。
# 读取Excel
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 写入Excel
with pd.ExcelWriter('output.xlsx') as writer:
df.to_excel(writer, sheet_name='原始数据', index=False)
你想想看,如果数据量不大(几千行以内),Excel完全够用。但一旦数据量上来了,Excel就扛不住了。这时候就需要二进制格式出场了。
3.2 二进制数据解析:与仪器直接对话
很多工业仪器输出的不是文本,而是二进制数据。为什么?因为二进制体积小、传输快。我见过一些老式的频谱仪,输出的就是二进制文件,一个文件几兆字节,但包含了几十万个数据点。
解析二进制数据,核心就是搞清楚数据格式。说白了,你得知道每个字节代表什么。
举个例子,假设仪器输出的数据格式是:前4个字节是时间戳(int32),后面每4个字节是一个浮点数(float32)。
import struct
import numpy as np
def parse_binary_file(filename):
with open(filename, 'rb') as f:
raw_data = f.read()
# 解析时间戳
timestamp = struct.unpack('<i', raw_data[:4])[0]
# 解析数据点
data_bytes = raw_data[4:]
num_points = len(data_bytes) // 4
data = np.frombuffer(data_bytes, dtype=np.float32)
return timestamp, data
struct.unpack解析固定长度的二进制数据,用numpy.frombuffer解析大量同类型数据。前者灵活,后者高效。
这里要注意字节序的问题。不同的仪器可能用大端序或小端序。我遇到过一台德国产的仪器,它用的是大端序,而我的电脑默认是小端序。结果解析出来的数据全是错的。解决办法很简单:在格式字符串里加个>或<。
# 大端序
timestamp = struct.unpack('>i', raw_data[:4])[0]
# 小端序
timestamp = struct.unpack('<i', raw_data[:4])[0]
3.3 HDF5大文件存储:海量数据的救星
当数据量达到GB级别时,CSV和Excel就彻底没戏了。这时候HDF5就派上用场了。
HDF5是一种分层数据格式,专门为大规模科学数据设计。它的特点是什么?快、压缩率高、支持随机访问。说白了,你不需要把整个文件读进内存,就能访问其中的任意一部分。
我在做振动信号分析时,经常要处理连续采集几小时的数据,文件大小动辄几十GB。用HDF5存储,读取速度比CSV快几十倍。
import h5py
import numpy as np
# 写入HDF5
with h5py.File('vibration_data.h5', 'w') as f:
f.create_dataset('time_series', data=np.random.randn(1000000))
f.create_dataset('metadata', data='采样率: 1000Hz')
# 读取HDF5
with h5py.File('vibration_data.h5', 'r') as f:
data = f['time_series'][:]
print(data.shape)
compression='gzip',压缩比大概在3-5倍。
# 带压缩的写入
f.create_dataset('big_data', data=large_array, compression='gzip', compression_opts=9)
嗯,这里要注意一点:HDF5虽然强大,但它的学习曲线稍微陡峭一些。不过一旦用上了,你就回不去了。
3.4 数据库存储(SQLite):结构化数据的最佳归宿
最后说说数据库。如果你的数据是结构化的(比如有明确的字段、需要频繁查询),那数据库就是最佳选择。
SQLite是嵌入式数据库,不需要安装服务器,一个文件就是一个数据库。非常适合仪器数据这种单机应用场景。
我为什么推荐SQLite?因为它零配置、跨平台、稳定可靠。我曾经在一个嵌入式仪器上跑SQLite,连续运行了三个月没出过问题。
import sqlite3
# 连接数据库(如果不存在则自动创建)
conn = sqlite3.connect('instrument.db')
cursor = conn.cursor()
# 创建表
cursor.execute('''
CREATE TABLE IF NOT EXISTS measurements (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
channel INTEGER,
value REAL
)
''')
# 插入数据
cursor.execute('''
INSERT INTO measurements (timestamp, channel, value)
VALUES (?, ?, ?)
''', ('2024-01-15 10:30:00', 1, 3.14159))
conn.commit()
# 查询数据
cursor.execute('SELECT * FROM measurements WHERE channel = ?', (1,))
rows = cursor.fetchall()
for row in rows:
print(row)
conn.close()
executemany,几秒钟就搞定了。
# 批量插入,效率提升百倍
data_batch = [
('2024-01-15 10:30:01', 1, 2.718),
('2024-01-15 10:30:02', 1, 3.142),
# ... 更多数据
]
cursor.executemany('INSERT INTO measurements VALUES (NULL, ?, ?, ?)', data_batch)
conn.commit()
另外,SQLite支持索引。如果你的查询经常按某个字段过滤,记得加索引。
cursor.execute('CREATE INDEX idx_channel ON measurements (channel)')
小结
好了,这一章的内容就到这里。我们来总结一下:
- CSV/Excel:适合小数据量、跨平台交换。注意编码问题。
- 二进制解析:适合与仪器直接通信。搞清楚字节序和数据结构是关键。
- HDF5:海量数据的首选。支持压缩和随机访问。
- SQLite:结构化数据的归宿。批量操作和索引是性能的关键。
我个人建议:在实际项目中,根据数据的特点选择合适的存储方式。没有银弹,只有最适合的方案。下一章我们会讲数据清洗与预处理,到时候这些读写技巧都会用上。
好,今天就到这里。有问题随时交流。