3. rawFs文件系统详解
大家好,我是老张。今天我们来聊聊VxWorks里一个比较"原始"但很实用的文件系统——rawFs。说实话,我刚接触VxWorks那会儿,总觉得rawFs这个名字听起来就有点"简陋",后来在项目中真正用上了,才发现它其实是个宝贝。
3.1 rawFs的创建
创建rawFs其实很简单。我习惯用rawFsDevCreate()这个函数。你想想看,它本质上就是在块设备上划出一块区域,然后按扇区来管理。
/* 创建一个rawFs文件系统 */
STATUS rawFsDevCreate
(
char * devName, /* 设备名称,比如"/rawFs/0" */
int blkDev, /* 块设备描述符 */
int startBlk, /* 起始块号 */
int nBlks /* 块数量 */
)
嗯,这里要注意几个参数。我在项目中遇到过有人把startBlk和nBlks搞反了,结果系统直接崩了。说白了,startBlk是起始位置,nBlks是你要占用的块数。
实际案例:我曾经在一个数据采集项目中,用rawFs来管理SD卡上的特定区域。当时的需求是:前1000个扇区留给系统日志,后面2000个扇区存采集数据。代码大概是这样的:
/* 创建两个rawFs分区 */
rawFsDevCreate("/rawFs/log", sdBlkDev, 0, 1000);
rawFsDevCreate("/rawFs/data", sdBlkDev, 1000, 2000);
3.2 rawFs的读写操作
rawFs的读写,说白了就是直接操作扇区。没有目录结构,没有文件名,就是纯粹的块读写。我个人觉得,这种"简单粗暴"的方式在某些场景下反而是优势。
读写操作主要用这两个函数:
/* 打开rawFs设备 */
int fd = open("/rawFs/data", O_RDWR, 0);
/* 读取数据 */
read(fd, buffer, nBytes);
/* 写入数据 */
write(fd, buffer, nBytes);
/* 别忘了关闭 */
close(fd);
我的小技巧:用lseek()可以精确定位到某个扇区。比如你要写第50个扇区,可以这样:
lseek(fd, 50 * SECTOR_SIZE, SEEK_SET);
write(fd, data, SECTOR_SIZE);
为什么会推荐这种方式?因为rawFs没有文件分配表,没有目录项,读写就是直接寻址。你想想看,少了这么多中间环节,速度能不快吗?
3.3 rawFs与dosFs的区别
这个问题我经常被问到。咱们直接上对比表:
| 特性 | rawFs | dosFs |
|---|---|---|
| 目录结构 | 无 | 有(树形目录) |
| 文件名 | 无 | 支持长文件名 |
| 读写方式 | 直接扇区读写 | 通过文件系统层 |
| 速度 | 极快 | 较慢(有开销) |
| 可靠性 | 高(无元数据) | 中等(有元数据损坏风险) |
| 跨平台 | 差 | 好(FAT格式通用) |
我记得有一次,一个同事非要用dosFs来存实时数据流,结果发现写入速度跟不上采样率。我建议他换成rawFs,问题立马解决了。说白了,dosFs虽然功能丰富,但那些目录、文件名、时间戳什么的,在实时数据采集场景下全是累赘。
避坑指南:我曾经遇到过一个问题——用rawFs存数据,突然掉电后,数据居然没丢!这其实是因为rawFs没有复杂的元数据要同步。但反过来,如果你需要文件管理功能,比如删除、重命名、目录浏览,那rawFs就完全帮不上忙了。
3.4 rawFs的应用场景
根据我的经验,rawFs最适合以下几个场景:
- 实时数据采集:比如传感器数据、音频流、视频流。不需要文件名,只需要按顺序存。
- 系统日志:循环写入日志,覆盖旧数据。用rawFs实现环形缓冲区特别方便。
- 启动加载器:Bootloader阶段,文件系统越简单越好,rawFs正合适。
- 临时缓存:比如网络数据包的临时存储,用完就丢。
实战经验分享:我在一个无人机飞控项目中,用rawFs来存储飞行参数。每10毫秒记录一次,数据量很大。如果用dosFs,每次写文件都要创建目录项、更新FAT表,开销太大了。换成rawFs后,直接按扇区写,速度提升了3倍多。
嗯,最后总结一下。rawFs虽然"原始",但它的简单、快速、可靠,在某些场景下是无可替代的。我个人建议:如果你的数据不需要文件管理,只需要快速读写,那就大胆用rawFs。但如果你需要跨平台兼容、文件管理功能,那还是老老实实用dosFs吧。
好了,这一章就到这里。下一章我们聊聊dosFs的详细用法,到时候会对比着讲,大家会更清楚什么时候该用哪个。