【发布时间】:2021-04-08 21:23:11
【问题描述】:
这是Conversion of string.endswith method into C 的后续,我正在(尝试)将python 程序转换为C。
下一部分是正确地将文件中的数据读取到缓冲区中,并检查可能出错的各个地方。到目前为止,这是我所拥有的:
#define BUFFER_SIZE 1024*10
char buffer[BUFFER_SIZE];
void exit_with_error(const char* msg)
{
fprintf(stderr, "%s", msg);
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[])
{
// with open(argv[-1) as f:
// contents = f.read()
// 1. Open file
FILE *fp = fopen(argv[argc-1], "r");
if (fp == NULL) exit_with_error("Error reading file");
// 2. Read and confirm BUFFER is OK
fseek(fp, 0L, SEEK_END);
long fsize = ftell(fp);
if (fsize > BUFFER_SIZE) exit_with_error("File is larger than buffer.");
// 3. Write to buffer and close.
rewind(fp);
size_t read_size = fread(buffer, 1, fsize, fp);
if (read_size != fsize) exit_with_error("There was an error reading the file.");
fclose(fp);
}
我对上述问题有几个问题:
- 对于将文件读入缓冲区,更常见的是具有标准缓冲区大小并将其写入缓冲区,还是获取大小然后执行
malloc。一种方式比另一种方式有优势吗? - 是否有必要在
main方法中进行所有这些错误检查,或者我可以假设用户提供了正确的文件(并且它是可读的,等等) - 最后,为什么有些文件方法返回
size_t,而另一些返回long(比如做ftell?)它们都使用size_t安全吗?不是那种类型?
【问题讨论】:
-
1.实在不好回答。这取决于上下文和要求。有时分配一个固定的缓冲区并分块读取是正确的做法。有时获取文件大小并分配完整的缓冲区是正确的。 2. 是的,这是必要的。依赖未经验证的用户输入或不检查函数返回值是灾难的根源。
-
至于问题 3:
size_t取决于您的编译器版本,对于 32 位编译器定义为unsigned int,对于 64 位编译器定义为unsigned long long。在选择要使用的类型时,最好遵循函数的声明。至于ftell,错误返回值之一是-1,它与unsigned类型不匹配。 -
@IradOhayon 也可以是
unsigned long。 -
如果
fopen失败,给出错误消息“读取文件时出错”是一种误导。读取文件没有错误。让系统给你一个很好的错误信息:FILE *fp = fopen(argv[argc-1], "r"); if (fp == NULL) { perror(argv[argc - 1]); exit(EXIT_FAILURE); }(或使用包装器并让包装器打印strerror(errno)) -
fseek/ftell组合不适用于获取文件的读取大小。并非每个文件都是可密封的,文件大小可能会在fseek和读取之间发生变化,并且一些奇怪的操作系统(又名 Windows)可能会在读取时进行文件翻译。将整个文件放入缓冲区的正确方法是循环读取文件,边写边写入缓冲区,直到 EOF,并根据需要调整缓冲区大小。更好的是没有整个文件缓冲区,而是在读取时处理数据。
标签: c