前言
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 系列無關,代碼如下:
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 測試代碼如下:
/* 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 : %sn", path);
fp = fopen(path, "w+");
if (!fp)
{
printf("fopen failedn");
return -1;
}
buffer = malloc(BUFFER_SIZE);
if (!buffer)
{
printf("buffer alloc failedn");
return -1;
}
file_size = get_file_size(path);
printf("file size %ldn", 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 %lun", so_far, signed_len, size);
if (signed_len - so_far < size)
size = signed_len - so_far;
printf("new size is %lun", size);
rd_len = fread(buffer, 1, size, fp);
printf("fread rd_len = %ldn", rd_len);
if ((rd_len != 0) && (rd_len != size))
{
printf("fread failed, rd_len = %ld, size = %ldn", rd_len, size);
fclose(fp);
free(buffer);
return -2;
}
so_far += size;
printf("fread so_far = %ldn", so_far);
}
fclose(fp);
free(buffer);
printf("fread big file test end!n");
return 0;
}
測試結果
文件大小 讀取 為 0
由于可以使用 qemu 來調試,我看看到底為何 大小為0,難道 打印的不對?
內核部分的 sys_stat 后面的調試就不放上來了,說明一個問題:文件獲取大小就是 0
回頭看下測試結果
好吧,我發現了文件系統BUG?讀取一下狀態,文件大小就變為 0 了?
我多試讀取了幾個文件,文件大小真的變為了0,包括 /lib/libc.so 這個默認文件
我在板子上試了一下,讀取了一下文件系統中的核心文件: rtthread.bin,哪想到,板子啟動不了,看了固件被【真正】清零0
趕快看看神奇的代碼
發現 BUG 了,原來在 獲取文件狀態前,有個 fopen 操作,并且使用了 "w+",就是這個問題
都是C 語言基礎薄弱惹的禍,記錄一下,以后得好好學習,正確理解,才能致用。
fopen 的 參數
當前發現 fopen 使用 “a+” 也不能獲取文件大小,二進制的文件,需要使用 “rb”
正常使用了 fopen 后,文件大小就正常獲取了
看來測試代碼,也需要認真寫,測試過程中【看似無關緊要】的代碼,也許就是個【地雷】
小結
以上記錄,其實就是 fopen 參數的使用方法的一個記錄,寫這么多,就是增加【印象】,得到【教訓】,防止編寫此類BUG 的事情不再重復犯。
-
二進制
+關注
關注
2文章
795瀏覽量
41668 -
C語言
+關注
關注
180文章
7605瀏覽量
136965 -
RT-Thread
+關注
關注
31文章
1291瀏覽量
40187 -
Ubuntu系統
+關注
關注
0文章
91瀏覽量
3962 -
gcc編譯器
+關注
關注
0文章
78瀏覽量
3387
發布評論請先 登錄
相關推薦
評論