Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
应用
RT-Smart 应用开发笔记:fopen 造成文件被清空问题的分析记录
发布于 2023-10-20 08:59:54 浏览:392
订阅该版
[tocm] ## 前言 - RT-Smart 应用(apps)开发环境,ubuntu 20.04 + win10 VS Code - 最近在调试一个问题,需要使用 `FILE` 的 fopen、fread 等去读取处理一个大文件,为了尽快复现验证问题,随手搜了一下 fopen 等几个 API的用法,调试时闹出来一个【笑话】,程序运行所到之处,把处理过的本地文件清空了。 - 当时初步的目标只是使用 `stat` 去获取一个文件的大小,现象就是 0 ## 获取文件大小 - 如何在 用户态获取文件大小,RT-Smart 的应用开发与 Linux 的用户应用开发基本类似,Linux 平台上的应用,可以轻松的移植到 RT-Smart 上。 - fopen 可以在RT-Smart内核态使用,也可以在用户态使用,用户态的使用,一般都是借助 libc 与 系统调用,当前 RT-Smart 使用 musl gcc 工具链 - 获取文件大小,应该与 fopen、fread 系列无关,代码如下: ```c unsigned long get_file_size(const char *path) { unsigned long filesize = -1; struct stat statbuff; if (stat(path, &statbuff) < 0) { return filesize; } else { filesize = statbuff.st_size; } return filesize; } ``` - 这里使用标准的 POSIX 接口 `stat`,头文件 `#include
` ## 测试代码 - 随手摘抄修改了一个测试代码,想获取到 文件大小,然后分批读取,验证这个过程是否正常,哪想到文件大小获取为0,使用 qemu 调试了多遍,怀疑文件系统BUG,依旧未找到正确的思路 - 原 BUG 测试代码如下: ```c /* read big file : > 300MB */ #include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE (8 * 1024 * 1024) unsigned long get_file_size(const char *path) { unsigned long filesize = -1; struct stat statbuff; if (lstat(path, &statbuff) < 0) { return filesize; } else { filesize = statbuff.st_size; } return filesize; } int main(int argc, char **argv) { //int errno; FILE *fp = NULL; unsigned long so_far, signed_len; const char *path = "/lib/libc.so"; char *buffer = NULL; size_t size; size_t file_size; size_t rd_len; if (argc > 1) { path = argv[1]; } printf("filename path : %s\n", path); fp = fopen(path, "w+"); if (!fp) { printf("fopen failed\n"); return -1; } buffer = malloc(BUFFER_SIZE); if (!buffer) { printf("buffer alloc failed\n"); return -1; } file_size = get_file_size(path); printf("file size %ld\n", file_size); signed_len = file_size; so_far = 0; while (so_far < signed_len) { size = BUFFER_SIZE; printf("so far is %lu, signed_len is %lu, size is %lu\n", so_far, signed_len, size); if (signed_len - so_far < size) size = signed_len - so_far; printf("new size is %lu\n", size); rd_len = fread(buffer, 1, size, fp); printf("fread rd_len = %ld\n", rd_len); if ((rd_len != 0) && (rd_len != size)) { printf("fread failed, rd_len = %ld, size = %ld\n", rd_len, size); fclose(fp); free(buffer); return -2; } so_far += size; printf("fread so_far = %ld\n", so_far); } fclose(fp); free(buffer); printf("fread big file test end!\n"); return 0; } ``` - 测试结果 - 文件大小 读取 为 0 ![2023-10-20_083936.png](https://oss-club.rt-thread.org/uploads/20231020/10cb62c83571cec158d00a7344540c65.png) - 由于可以使用 qemu 来调试,我看看到底为何 大小为0,难道 打印的不对? ![2023-10-20_084236.png](https://oss-club.rt-thread.org/uploads/20231020/8a5527308f8d52fcac730149a49e2e87.png.webp) ![2023-10-20_084510.png](https://oss-club.rt-thread.org/uploads/20231020/356e5983e4be41c15fca39723efe11c4.png) ![2023-10-20_084609.png](https://oss-club.rt-thread.org/uploads/20231020/7212f4be98ddc4b2b0008ae9f3146c73.png.webp) - 内核部分的 `sys_stat` 后面的调试就不放上来了,说明一个问题:文件获取大小就是 0 ## 回头看下测试结果 - 好吧,我发现了文件系统BUG?读取一下状态,文件大小就变为 0 了? - 我多试读取了几个文件,文件大小真的变为了0,包括 `/lib/libc.so` 这个默认文件 - 我在板子上试了一下,读取了一下文件系统中的核心文件: `rtthread.bin`,哪想到,板子启动不了,看了固件被【真正】清零0 ![2023-10-20_084842.png](https://oss-club.rt-thread.org/uploads/20231020/aa99067477c056299402dd806c4b6716.png) ## 赶快看看神奇的代码 - 发现 BUG 了,原来在 获取文件状态前,有个 fopen 操作,并且使用了 `"w+"`,就是这个问题 ![微信图片_20231019145449.png](https://oss-club.rt-thread.org/uploads/20231020/a63bdbf83b631af8a8ba3b5bbf058001.png) ![微信图片_20231019145457.png](https://oss-club.rt-thread.org/uploads/20231020/5314b3f359d781ef5f0336bce0dafe0b.png) ![微信图片_20231019145501.png](https://oss-club.rt-thread.org/uploads/20231020/c4bc416255dacaca9cb3fc451bd3edce.png) - 都是C 语言基础薄弱惹的祸,记录一下,以后得好好学习,正确理解,才能致用。 ## fopen 的 参数 - 当前发现 fopen 使用 "a+" 也不能获取文件大小,二进制的文件,需要使用 "rb" ![2023-10-20_085533.png](https://oss-club.rt-thread.org/uploads/20231020/88b2645b37ed82bd8c92b1da10fb50b7.png) - 正常使用了 fopen 后,文件大小就正常获取了 ![2023-10-20_090701.png](https://oss-club.rt-thread.org/uploads/20231020/93d0e51ecae89b2bdfd7c0cdcd2741b0.png) - 看来测试代码,也需要认真写,测试过程中【看似无关紧要】的代码,也许就是个【地雷】 ## 小结 - 以上记录,其实就是 fopen 参数的使用方法的一个记录,写这么多,就是增加【印象】,得到【教训】,防止编写此类BUG 的事情不再重复犯 - 获取知识途径很多,有时候有些 BUG的出现,会针对性的让你获取更多,嵌入式开发,除了博闻强记,更重要的,就是有个【烂笔头】记录点点滴滴。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
804
被采纳
174
关注TA
发私信
相关文章
1
请问各位都是怎么学会的RTOS呢?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部