提问人:Shepard Merose 提问时间:12/15/2022 最后编辑:Shepard Merose 更新时间:12/15/2022 访问量:168
读取文件时遇到EOF不正确
Encountered EOF incorrectly while reading file
问:
以下是我的程序。我尝试读取文件并将其数据传输到 . 很长,大约有 270 万行,但是当我运行程序并检查时;它只有 250 万行(准确地说是 2554994 行),这意味着在这一行中,程序读取到 EOF。但是,情况并非如此。我不知道出了什么问题rgb_values.txt
out.txt
rgb_values.txt
out.txt
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include <stdio.h>
int count=0;
void getOneByte(FILE *plaintext,unsigned char *pt,int i){
char line[4]={0x0};
fgets(line,sizeof(line),plaintext);
int x1=0x0;
char str[4];
sprintf(str,"%s",line);
sscanf(str,"%02x ",&x1);
pt[i]=x1;
}
void get16Bytes(FILE *plaintext,unsigned char * pt){
int i=0;
char sh;
for (int i = 0; i <=15; i++)
{
getOneByte(plaintext,pt,i);
if((sh=fgetc(plaintext))!=EOF){
ungetc(sh,plaintext);
}
else{
ungetc(sh,plaintext);
break;
}
}
}
void write16Bytes(FILE *ciphertext,unsigned char *ct){
int i;
for(i = 0; i < 16; i++){
if(count == 0){
fprintf(ciphertext,"%02x",ct[i]);
count++;
}
else if(count == 1){
fprintf(ciphertext," %02x",ct[i]);
count++;
}
else if(count == 2){
fprintf(ciphertext," %02x\n",ct[i]);
count = 0;
}
}
}
int main(){
FILE *fp=fopen("rgb_values.txt","r");
FILE *fo=fopen("out.txt","w");
char ch;
unsigned char pt[16];
int i=15;
int cnt=0;
while(1){
memset(pt,'a',sizeof(pt));
get16Bytes(fp,pt);
if((ch=fgetc(fp))!=EOF){
ungetc(ch,fp);
}
else{
break;
}
write16Bytes(fo,pt);
cnt++;
}
fclose(fp);
return 1;
}
我的输入文件的一部分:
c1 c1 c1
ff ff ff
ff ff ff
ff ff ff
ff ff ff
fe fe fe
fd fd fd
ff ff ff
fb fb fb
fe fe fe
fe fe fe
ff ff ff
fb fb fb
f1 f1 f1
e9 e9 e9
e6 e6 e6
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e5 e5 e5
e2 e2 e2
e5 e5 e5
e7 e7 e7
e5 e5 e5
e4 e4 e4
e3 e3 e3
e3 e3 e3
e8 e8 e8
de de de
9c 9c 9c
3b 3b 3b
01 01 01
02 02 02
00 00 00
02 02 02
0a 0a 0a
答:
我不知道出了什么问题
编码不是防御性的,因为它不会寻找意外事件。
要了解出了什么问题,请改进代码的错误检测。
换句话说,不要相信用户输入——这是邪恶的。
为什么只读取 3 个字节?
下面从文件中读取最多 3 个字节,将一行的其余部分留给以后读取。
char line[4]={0x0};
fgets(line,sizeof(line),plaintext);
它不会只从文件中读取 3 个字节并抛弃该行的其余部分。
检查 fgets()
的返回值
// fgets(line,sizeof(line),plaintext);
if (fgets(line,sizeof(line),plaintext) == NULL) {
TBD_alert();
}
使用 int
int fgetc()
可以返回 257 个不同的值。储蓄会失去一些东西。char
// char ch;
int ch;
// char sh;
int sh;
缺乏错误检查
如果返回 0(无转换)怎么办?sscanf(str,"%02x ",&x1)
如果 4 太小怎么办?
如果存在额外的空格 (space, , ...),则 4 太小了。'\r'
char line[4]={0x0};
fgets(line,sizeof(line),plaintext);
相反,读取一整行,允许至少 2 倍大小的缓冲区超过预期大小,并容忍额外的空格或最后一行的缺失。给定一行 ,使用缓冲区大小 (3*3 + 1)*2。fgets()
'\n'
"c1 c1 c1\n"
我怀疑有很多潜伏在周围。'\r'
避免UB。使用匹配说明符
"%x"
匹配 ,而不是 。unsigned
int
// int x1=0x0;
unsigned x1 = 0x0;
...
// '0' is useless, '2' is not needed. Trailing space is useless
// sscanf(str,"%02x ",&x1);
sscanf(str,"%x", &x1); // Check return value - not shown
或直接保存
sscanf(str, "%hhx", &pt[i]);
每行 3 个值之外还有什么?
读取一行 3 个十六进制值并检测大量错误的示例代码。
#define EXPECTED_LINE_SIZE (3*3 + 1 /* for the \0 */)
char line[EXPECTED_LINE_SIZE * 2];
if (fgets(line, sizeof line, plaintext) == NULL) {
return failure;
}
int n = 0;
unsigned val[3];
sscanf(line "%2x %2x %2x %n", &val[0], &val[1], &val[2], &n);
if (n == 0 || line[n] != '\0') {
return failure;
}
检查 fopen()
是否失败
FILE *fp=fopen("rgb_values.txt","r");
FILE *fo=fopen("out.txt","w");
if (fp == NULL || fo == NULL) {
TBD_Error_out(); // Add your code here
}
评论
TBD_alert
return failure
如果您只想从一个文件复制到另一个文件,请以二进制模式打开,并在循环中打开一个 4KiB 的缓冲区,然后将其复制到另一个文件。方便快捷:fread
fwrite
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *in = fopen(..., "rb");
FILE *out = fopen(..., "wb");
if (!in || !out)
return EXIT_FAILURE;
char buffer[4096];
size_t nread;
while ((nread = fread(buffer, 1, sizeof buffer, in)) > 0)
fwrite(buffer, 1, nread, out);
}
否则,如果您需要将其作为字符串读取,请在循环中使用:fgets
fputs
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *in = fopen(..., "r");
FILE *out = fopen(..., "w");
if (!in || !out)
return EXIT_FAILURE;
char line[256];
while (fgets(line, sizeof line, in) != NULL)
fputs(line, out);
}
或者正如我所提到的,要读取一整行,解析出所有三个值,传回调用函数(连同文件读取成功状态),并同时读取所有三个值:fgets
sscanf
fprintf
#include <stdio.h>
#include <stdlib.h>
int read_values(FILE *in, int *values)
{
char line[256];
if (fgets(line, sizeof line, in) == NULL)
return 0; // Failure to read
if (sscanf(line("%x %x %x", &values[0], &values[1], &values[2]) != 3)
return 0; // Failure to parse
return 1; // Success
}
void write_values(FILE *out, int *values)
{
fprintf(out, "%02x %02x %02x\n", values[0], values[1], values[2]);
}
int main(void)
{
FILE *in = fopen(..., "r");
FILE *out = fopen(..., "w");
if (!in || !out)
return EXIT_FAILURE;
int values[3];
while (read_values(in, values))
write_values(out, values);
}
请注意,我不会关闭文件。如果你的程序在此之后做了更多的事情,那么它们真的应该被关闭。如果程序刚刚退出,那么系统将为我们关闭它们。
上一个:如何模拟EOF?
评论
getOneByte
sscanf
line
strtol
pt[i]
x1
fgetc
返回一个int
值。当您想与 值进行比较时,这非常重要。int
EOF
count
static
count