You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用fgetc()读取文件时字符丢失,添加fseek()回退才正常,求原因解释

fgetc()读取文件字符被跳过的原因分析

我在使用fgetc()读取文件时遇到字符被跳过的问题,只有调用fseek()将文件指针回退一位后,程序才能正常运行,完全无法理解为何需要通过fseek()来解决该问题,希望有人能帮我解释其中原因。

出现字符跳过的代码

int file_chars = 0;
size_t hdr_size = 15;
char hdr_cook_val[hdr_size];
esp_err_t get_cookie = httpd_req_get_cookie_val(req,COOKIE_NAME,hdr_cook_val,&hdr_size);
if(get_cookie == ESP_ERR_NOT_FOUND && req->uri[0] == '/' && req->method == HTTP_GET){
     FILE *index_file = fopen(HTML_PART_FOLDER"/index.txt","r");
     char *hdr_val = malloc(sizeof(char)*MALLOC_DEFAULT_SIZE);
     if(hdr_val==NULL){ESP_LOGE(TAG,"Malloc failed variable name: hdr_val");return ESP_OK;}
     for(int i=0;;i++){
         file_chars = fgetc(index_file);
         if(file_chars==EOF){
             httpd_resp_send_chunk(req,hdr_val,i);
             httpd_resp_send_chunk(req,NULL,0);
             break;
         }
         hdr_val[i] = file_chars;
         if(i==9999){
             httpd_resp_send_chunk(req,hdr_val,i);
             i=-1;
             vTaskDelay(pdMS_TO_TICKS(20));
         }
     }
     free(hdr_val);
     fclose(index_file);
     return ESP_OK;
}

添加fseek修复后的代码

int file_chars = 0;
size_t hdr_size = 15;
char hdr_cook_val[hdr_size];
esp_err_t get_cookie = httpd_req_get_cookie_val(req,COOKIE_NAME,hdr_cook_val,&hdr_size);
if(get_cookie == ESP_ERR_NOT_FOUND && req->uri[0] == '/' && req->method == HTTP_GET){
     FILE *index_file = fopen(HTML_PART_FOLDER"/index.txt","r");
     char *hdr_val = malloc(sizeof(char)*MALLOC_DEFAULT_SIZE);
     if(hdr_val==NULL){ESP_LOGE(TAG,"Malloc failed variable name: hdr_val");return ESP_OK;}
     for(int i=0;;i++){
         file_chars = fgetc(index_file);
         if(file_chars==EOF){
             httpd_resp_send_chunk(req,hdr_val,i);
             httpd_resp_send_chunk(req,NULL,0);
             break;
         }
         hdr_val[i] = file_chars;
         if(i==9999){
             httpd_resp_send_chunk(req,hdr_val,i);
             fseek(index_file,ftell(index_file)-1,SEEK_SET);
             i=-1;
             vTaskDelay(pdMS_TO_TICKS(20));
         }
     }
     free(hdr_val);
     fclose(index_file);
     return ESP_OK;
}

问题原因解析

问题出在循环处理10000字符的逻辑上:

  • 当循环变量i走到9999时,程序已经执行fgetc()读取了第10000个字符(i从0开始计数),并把这个字符存在了hdr_val[9999]里。
  • 但调用httpd_resp_send_chunk(req,hdr_val,i)时,传入的长度是i=9999,这意味着只发送了hdr_val[0]到hdr_val[9998]这9999个字符,刚读取的hdr_val[9999]并没有被发送。
  • 之后你把i设为-1,下一次循环i会自增为0,再次调用fgetc()时,文件指针已经指向了下一个字符,导致hdr_val[9999]里的那个字符被永远跳过。

添加fseek(index_file,ftell(index_file)-1,SEEK_SET)的作用,就是把文件指针回退一位,让下一次fgetc()能重新读取那个没被发送的字符,把它存在hdr_val[0]里,后续发送的时候就不会丢失了。

另外补充一个更合理的修复方式:把发送长度改成i+1,这样就能一次性发送10000个字符,也就不需要回退文件指针了:

if(i==9999){
    httpd_resp_send_chunk(req,hdr_val,i+1); // 将长度参数从i改为i+1
    i=-1;
    vTaskDelay(pdMS_TO_TICKS(20));
}

内容的提问来源于stack exchange,提问作者mafia2g2001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 05:10:36