C 中 fread () 和 fwrite () 函数的问题
Issue with fread () and fwrite () functions in C
我写了一个基本代码,它以二进制模式将字符串写入文件(使用 fwrite())。我也可以从文件中读取相同的字符串(使用 fread())到缓冲区并打印它。它有效,但在我从文件中读取的部分,额外的垃圾也被读入缓冲区。我的问题是如何正确知道要读取的字节长度?
下面是代码--
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define BUFSZ 81
char * get_string (char *, size_t);
int main (int argc, char * argv[])
{
if (argc != 2)
{
fprintf (stderr, "Invalid Arguments!!\n");
printf ("syntax: %s <filename>\n", argv[0]);
exit (1);
}
FILE * fp;
if ((fp = fopen(argv[1], "ab+")) == NULL)
{
fprintf (stderr, "Cannot openm file <%s>\n", argv[1]);
perror ("");
exit (2);
}
char string[BUFSZ];
char readString[BUFSZ];
size_t BYTES, BYTES_READ;
puts ("Enter a string: ");
get_string (string, BUFSZ);
// printf ("You have entered: %s\n", string);
BYTES = fwrite (string, sizeof (char), strlen (string), fp);
printf ("\nYou have written %zu bytes to file <%s>.\n", BYTES, argv[1]);
printf ("\nContents of the file <%s>:\n", argv[1]);
rewind (fp);
BYTES_READ = fread (readString, sizeof (char), BUFSZ, fp);
printf ("%s\n", readString);
printf ("\nYou have read %zu bytes from file <%s>.\n", BYTES_READ, argv[1]);
getchar ();
fclose (fp);
return 0;
}
char * get_string (char * str, size_t n)
{
char * ret_val = fgets (str, n, stdin);
char * find;
if (ret_val)
{
find = strchr (str, '\n');
if (find)
* find = '[=10=]';
else
while (getchar () != '\n')
continue;
}
return ret_val;
}
in the part where I read from the file, extra junk is also read into the buffer.
不,不是。由于您正在以附加模式打开文件,因此您可能正在读取额外数据 preceding 您所写的字符串,但您没有读取任何超过 what 结尾的内容你写了,因为那里没有什么可读的。当文件最初为空或不存在时,您可以通过比较 BYTES
的值与 BYTES_READ
.
的值来验证这一点
您实际看到的是 read-back 数据未被空终止的效果。您没有将终止符写入文件,因此无法读回。避免写入终止符可能是合理的,但在这种情况下,您必须在读回数据时提供一个新终止符。例如,
readString[BYTES_READ] = '[=10=]';
My question is how to know the length of the bytes to be read, correctly?
有多种可能性。其中比较突出的有
- 使用fixed-length数据
- 将字符串长度写入文件,先于字符串数据。
或者,在您的特定情况下,当文件开始为空并且您只在其中写入一个字符串时,也有可能捕获并处理多少字节 were阅读而不是提前知道应该阅读多少。
首先你从用户那里得到 string
,它最多包含 BUFSZ-1
个字符(get_string()
函数将删除结尾的换行符或跳过任何超过 BUFSZ 限制的字符.
例如,用户可能插入了单词 Hello\n
,因此在 get_string()
调用 string
之后,数组包含
-------------------
|H|e|l|l|o|'[=10=]'|...
-------------------
然后你 fwrite
将 string
缓冲区写入输出文件,写入 strlen (string)
字节。 这不包括字符串终止符 '[=26=]'
。
在我们的示例中,输出文件的内容是
--------------
|H|e|l|l|o|...
--------------
你终于从文件中读回来了。但由于 readString
数组未初始化,文件内容后跟未初始化数组中可能存在的每个垃圾字符。
例如,readString
可以有以下初始内容:
---------------------------------------------
|a|a|a|a|a|T|h|i|s| |i|s| |j|u|n|k|!|'[=12=]'|...
---------------------------------------------
并在读取文件后
---------------------------------------------
|H|e|l|l|o|T|h|i|s| |i|s| |j|u|n|k|!|'[=13=]'|...
---------------------------------------------
以便打印以下字符串
HelloThis is junk!
为了避免这些问题,您必须确保目标缓冲区中存在尾随终止符。因此,只需以这种方式初始化数组:
char readString[BUFSZ] = { 0 };
这样,目标数组中至少会出现一个字符串终止符。
或者,在每次读取之前将其 memset 为 0:
memset (readString, 0, BUFSZ);
我写了一个基本代码,它以二进制模式将字符串写入文件(使用 fwrite())。我也可以从文件中读取相同的字符串(使用 fread())到缓冲区并打印它。它有效,但在我从文件中读取的部分,额外的垃圾也被读入缓冲区。我的问题是如何正确知道要读取的字节长度?
下面是代码--
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define BUFSZ 81
char * get_string (char *, size_t);
int main (int argc, char * argv[])
{
if (argc != 2)
{
fprintf (stderr, "Invalid Arguments!!\n");
printf ("syntax: %s <filename>\n", argv[0]);
exit (1);
}
FILE * fp;
if ((fp = fopen(argv[1], "ab+")) == NULL)
{
fprintf (stderr, "Cannot openm file <%s>\n", argv[1]);
perror ("");
exit (2);
}
char string[BUFSZ];
char readString[BUFSZ];
size_t BYTES, BYTES_READ;
puts ("Enter a string: ");
get_string (string, BUFSZ);
// printf ("You have entered: %s\n", string);
BYTES = fwrite (string, sizeof (char), strlen (string), fp);
printf ("\nYou have written %zu bytes to file <%s>.\n", BYTES, argv[1]);
printf ("\nContents of the file <%s>:\n", argv[1]);
rewind (fp);
BYTES_READ = fread (readString, sizeof (char), BUFSZ, fp);
printf ("%s\n", readString);
printf ("\nYou have read %zu bytes from file <%s>.\n", BYTES_READ, argv[1]);
getchar ();
fclose (fp);
return 0;
}
char * get_string (char * str, size_t n)
{
char * ret_val = fgets (str, n, stdin);
char * find;
if (ret_val)
{
find = strchr (str, '\n');
if (find)
* find = '[=10=]';
else
while (getchar () != '\n')
continue;
}
return ret_val;
}
in the part where I read from the file, extra junk is also read into the buffer.
不,不是。由于您正在以附加模式打开文件,因此您可能正在读取额外数据 preceding 您所写的字符串,但您没有读取任何超过 what 结尾的内容你写了,因为那里没有什么可读的。当文件最初为空或不存在时,您可以通过比较 BYTES
的值与 BYTES_READ
.
您实际看到的是 read-back 数据未被空终止的效果。您没有将终止符写入文件,因此无法读回。避免写入终止符可能是合理的,但在这种情况下,您必须在读回数据时提供一个新终止符。例如,
readString[BYTES_READ] = '[=10=]';
My question is how to know the length of the bytes to be read, correctly?
有多种可能性。其中比较突出的有
- 使用fixed-length数据
- 将字符串长度写入文件,先于字符串数据。
或者,在您的特定情况下,当文件开始为空并且您只在其中写入一个字符串时,也有可能捕获并处理多少字节 were阅读而不是提前知道应该阅读多少。
首先你从用户那里得到 string
,它最多包含 BUFSZ-1
个字符(get_string()
函数将删除结尾的换行符或跳过任何超过 BUFSZ 限制的字符.
例如,用户可能插入了单词 Hello\n
,因此在 get_string()
调用 string
之后,数组包含
-------------------
|H|e|l|l|o|'[=10=]'|...
-------------------
然后你 fwrite
将 string
缓冲区写入输出文件,写入 strlen (string)
字节。 这不包括字符串终止符 '[=26=]'
。
在我们的示例中,输出文件的内容是
--------------
|H|e|l|l|o|...
--------------
你终于从文件中读回来了。但由于 readString
数组未初始化,文件内容后跟未初始化数组中可能存在的每个垃圾字符。
例如,readString
可以有以下初始内容:
---------------------------------------------
|a|a|a|a|a|T|h|i|s| |i|s| |j|u|n|k|!|'[=12=]'|...
---------------------------------------------
并在读取文件后
---------------------------------------------
|H|e|l|l|o|T|h|i|s| |i|s| |j|u|n|k|!|'[=13=]'|...
---------------------------------------------
以便打印以下字符串
HelloThis is junk!
为了避免这些问题,您必须确保目标缓冲区中存在尾随终止符。因此,只需以这种方式初始化数组:
char readString[BUFSZ] = { 0 };
这样,目标数组中至少会出现一个字符串终止符。
或者,在每次读取之前将其 memset 为 0:
memset (readString, 0, BUFSZ);