21、传感器数据导出:将采集的数据导出为CSV文件,方便在PC上做进一步分析
好,咱们终于到了数据导出这一步。说实话,前面折腾了那么多传感器采集、滤波、校准,最终目的不就是为了拿到干净的数据,然后做分析吗?我个人习惯是把数据导出成CSV格式,因为Excel、Python、MATLAB都能直接打开,省去一堆格式转换的麻烦。
为什么非得是CSV?
你想想看,我们在手机上采集的光线数据,本质就是一串带时间戳的数字。CSV(逗号分隔值)这种格式,说白了就是纯文本表格。它有几个好处:
- 通用性极强:任何系统、任何软件都能读
- 体积小:比Excel文件小得多,适合大量传感器数据
- 可读性好:用记事本打开也能看,调试方便
- 无版权问题:不像某些专有格式需要特定软件
核心思路:把SensorEvent里的时间戳和光照值,一行一行写到文件里,每行用逗号隔开。就这么简单。
数据导出的标准格式
我在项目中遇到过不少坑,比如时间戳格式不统一、数值精度丢失、中文乱码等等。后来我总结了一套比较稳的格式:
| 列名 | 说明 | 示例 |
|---|---|---|
| timestamp | Unix时间戳(毫秒) | 1712345678000 |
| timestamp_human | 可读时间(ISO 8601) | 2024-04-06 10:30:00.123 |
| lux | 光照强度(勒克斯) | 320.5 |
| accuracy | 传感器精度等级 | 3 |
我的小技巧:同时保留机器时间戳和人类可读时间。机器时间戳方便排序和计算差值,人类可读时间方便肉眼检查。两列都留着,不冲突。
代码实现:从采集到导出
嗯,这里要注意一个关键点:文件写入操作不能放在UI线程里做。我曾经犯过这个错,结果界面卡得跟幻灯片似的。正确的做法是用后台线程或者协程来处理。
下面是我常用的一个导出工具类,你直接拿去用就行:
public class CsvExporter {
private static final String CSV_HEADER = "timestamp,timestamp_human,lux,accuracy\n";
public static File exportToCsv(Context context, List<SensorData> dataList, String fileName) {
File file = new File(context.getExternalFilesDir(null), fileName);
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
// 写入表头
bw.write(CSV_HEADER);
// 逐行写入数据
for (SensorData data : dataList) {
StringBuilder line = new StringBuilder();
line.append(data.timestamp).append(",");
line.append(formatTimestamp(data.timestamp)).append(",");
line.append(data.lux).append(",");
line.append(data.accuracy).append("\n");
bw.write(line.toString());
}
bw.flush();
return file;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static String formatTimestamp(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault());
return sdf.format(new Date(millis));
}
}
避坑指南:我曾经在导出大量数据时忘了加flush(),结果文件里少了一半数据。记得在写入完成后调用flush(),或者用try-with-resources自动关闭流。
数据采集与导出的完整流程
为了让整个流程更清晰,我画了一张图。你看一眼就明白数据是怎么从传感器一路走到CSV文件的:
导出后的数据长什么样?
导出完成后,你用Excel打开CSV文件,应该能看到类似这样的数据:
timestamp,timestamp_human,lux,accuracy
1712345678000,2024-04-06 10:30:00.000,320.5,3
1712345678010,2024-04-06 10:30:00.010,321.2,3
1712345678020,2024-04-06 10:30:00.020,319.8,3
1712345678030,2024-04-06 10:30:00.030,322.1,3
你看,每一行就是一次传感器采样。时间戳精确到毫秒,光照值保留一位小数。这样的数据拿到PC上,用Python的pandas库一读,画个折线图,光照变化趋势一目了然。
我的经验:如果你打算用Python做后续分析,建议在CSV里多加一列「event_delta」,即相邻两次采样的事件间隔。这样你可以检查传感器是否出现了丢帧或者采样不均匀的情况。
导出文件的管理
数据导出了,文件放哪儿也是个问题。我个人习惯把文件放在应用的专属外部存储目录里:
// 获取应用专属的外部存储目录
File exportDir = context.getExternalFilesDir("sensor_data");
// 实际路径类似:/storage/emulated/0/Android/data/你的包名/files/sensor_data/
这样做的好处是:
- 不需要申请存储权限(Android 10以上)
- 卸载应用时文件自动删除,不污染用户存储
- 通过USB连接电脑后,这个目录可见,可以直接复制
曾经踩过的坑:我一开始把文件存在了公共的Downloads目录,结果用户卸载应用后留下一堆垃圾文件。后来改成getExternalFilesDir,清爽多了。而且Android 11开始对公共目录的访问限制更严,用专属目录反而省事。
好了,数据导出这块就这些。你只要按照上面的流程走,从传感器采集到CSV文件落地,基本不会出大问题。拿到数据后,你就可以在PC上尽情分析了——画曲线、算平均值、做FFT,都随你。