使用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
相关产品推荐
相关产品推荐

