我写了一段代码来读取一个文件。读取默认文件或另一个文件,并将内容文件存储在字符串中。我不知道我错在哪里!当我运行它时,有时它是好的,但有时我会得到一个Core Dump错误!
下面是我的代码:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define EXAMPLE_FILE "programing_languages.example"
#define EXAMPLE_FILE_SIZE strlen(EXAMPLE_FILE)+1
int read_file(char *buffer, char *file_name)
{
FILE *file;
file = fopen(file_name, "r");
if (file == NULL)
{
printf("Warning!!!");
return 1;
}
fread(buffer, sizeof(char), BUFFER_SIZE, file);
fclose(file);
return 0;
}
int main(int argc, char *argv[])
{
int opt;
int file_name_customized = 0;
char *file_name;
while ((opt = getopt(argc, argv, "f:")) != -1) {
switch (opt) {
case 'f':
snprintf(file_name, strlen(argv[2])+1, "%s", argv[2]);
file_name_customized = 1;
break;
default:
snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
}
}
if (!file_name_customized)
{
snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
}
char buffer[BUFFER_SIZE] = {"\0"};
if (read_file(buffer, EXAMPLE_FILE) == 1)
{
printf("Got Error To Open %s File!\n", file_name);
return errno;
}
printf("%s\n", buffer);
}
字符串
我想读取一个文件并将其保存为字符串。(C语言)
4条答案
按热度按时间bqujaahr1#
你有很多错误的假设。我会给你一点关于黑暗的启示,给予
1.在下面的代码中,你误用了
snprintf
:字符串
snprintf
的前两个参数必须用缓冲区指针填充(有效指针,而不是未初始化的指针)和缓冲区大小(已经从optarg
原始文件中计算出来)您假设缓冲区将在snprintf
内部构建,但这是不可能的(你通过值传递指针,复制它的值,所以例程不可能改变它可能具有的未知和不可预测的值:在调用snprintf()
* 之前,有一种正确的方法(因为你可以知道命令行参数的字符串长度)来做这件事 *:型
或者简单地说,如果您不打算触摸
file_name
内容:型
(note:使用
optarg
的原因是你使用的argv[2]
不需要是-f
选项的参数的位置,你可以按照你喜欢的任何顺序指定getopt()
的选项,所以如果你有更多的选项,你可以在指定-f
之前指定其他选项,该选项将是-f
位置之后的参数(这是由getopt()
全局变量optarg
指向的,如getopt(1)中所述)。1.函数
read_file()
不知道缓冲区的 * 实际 * 大小。它只是假设它是BUFFER_SIZE
,通常这是不正确的(如果你将它用于其他大小不同的缓冲区)。如果你将缓冲区大小作为参数传递给函数会更好(就像snprintf()
在标准库中所做的那样):型
1.接下来,在
main()
中,您假设缓冲区已被填充并以'\0'
字符终止,因为%s
说明符需要知道字符串结束的位置。这是不正确的,您的文件可以包含'\0'
字符,这将提前结束文件的打印,或者更糟,可以没有'\0'
字符,并使printf()
继续尝试访问缓冲区内容,并失败到未定义的行为(这可能是你有时欣赏)一般来说,如果你只处理文本文件,你可以假设你的文件不会有
'\0'
字符,并添加它(但你需要这样做,fread()
没有)如下:型
但是如果你只是想打印一个文件的内容,你可以直接做(更简单的解决方案,不需要缓冲,因为 stdio package已经以透明的方式进行缓冲),并且不受缓冲区大小的限制(所以你可以打印文件的文件内容,文件的字节数更大)。
型
这有一些好处:
1.你不需要做缓冲区管理(stdio自动为你做的事情)
1.您可以使用该程序的两个接口:a)使用
-f
选项指定文件,或者B)通过从shell重定向标准输入1.越简单越好。
或者,如果你想要一个函数来做所有的文件工作:
型
最后一种方法(在我们处理选项时处理文件)允许您添加多个
-f
选项,如:型
将
a.c
复制三次到标准输出(就像unixcat
命令一样)nhn9ugyo2#
代码在许多方面都很脆弱。
BUFFER_SIZE
,read_file()
将失败。\0
来结束读取的字节序列,除非文件的确切大小是BUF_SIZE-1
,所以字符串
并且
printf()
调用将失败。也
read_file()
时,使用EXAMPLE_FILE
代替file_name
。getopt()
有点太多了,当程序的单一目的是加载和打印一个用文件内容构建的字符串时:只需使用文件名。3个示例
下面是在
C
中执行此操作的3个简单示例。所有3个编译器在微软编译器和
gcc
下编译,并运行正常。示例中使用的文件是
28.txt
,大小为28字节型
在许多情况下,我们需要更改
\n
的编码。我现在在Windows中,默认内容是型
我们看到
\n
使用2个字节作为0x0d0a
示例1:一次性读取文件
型
该计划只是
stat
获取文件大小型
示例2:根据需要使用扩展缓冲区
这个方法使用了一个初始缓冲区,并根据需要进行扩展。其思想是分配一个足够大的缓冲区,以便在单次读取中容纳大多数预期文件,但随后根据需要扩展它以容纳大于初始块的文件。
这里使用的缓冲区只有4个字节,这只是为了测试.使用更大的东西,如1MB。
型
重要的部分是循环内部,围绕
realloc
的逻辑和缓冲区大小的变化。型
示例3:将文件作为指向各行的指针数组上传
一般来说,这是更有用的方式,因为在加载后我们可以直接访问原始文件的任何一行。作为一个例子,这里输入文件被排序,然后再次 * 打印 *。
以下是用于保存文件的
struct
:型
以及用于加载文件、显示其内容等的方法。
main
程序可以简单地转换为:load_file()
。型
完整代码
型
示例输出
型
aelbi1ox3#
如何读取文件并将内容保存为字符串?
1.打开文件。检查错误。
1.通过
fread()
读取整个文件,使用一个大小合适的缓冲区,比如4K,并对返回的长度求和。1.继续第2步,直到出现错误或未读取任何内容。
1.分配sum + 1。检查分配是否成功。
1.重新读取整个文件,将1
fread()
放入分配的缓冲区。注意返回的长度。1.关闭档案。
1.追加一个 *null字符 *。
1.如果长度符合预期,则成功,否则失败。
1.返回分配的指针,失败时返回NULL。
ehxuflar4#
其中一个答案告诉你要读两遍文件,但没有解释为什么。下面是解释。
确定文件大小的常用方法是使用
fseek
/ftell
。将文件的读指针设置为文件的结尾;那么它的位置将告诉文件的大小。这种方法适用于二进制文件(您以"rb"
模式打开的文件),但用于文本文件("r"
)它是不准确的。在常见的情况下,不准确的唯一原因是从\r\n
到\n
在Windows上的转换。因为它的确定分配一个更大的缓冲区,你可以使用这个方法来读取整个文件。字符串
这种常用的方法不能保证有效:这样使用时,
ftell
的输出在技术上是不确定的;但在实践中,它应该可以工作。在以下情况下它会失败:wchar_t
字符的文件)LONG_MAX
,可能等于2 GB)