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=]'|...
-------------------

然后你 fwritestring 缓冲区写入输出文件,写入 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);