fread 只从我第一次 运行 开始阅读程序

fread only reading in from the first time I ran the program

当我第一次 运行 我会添加 3 条记录,这给了我 3 的计数。然后我 fwrite 将计数存入一个 bin 文件,然后将记录存入一个 bin 文件,然后我关闭程序。

当我重新打开它然后我 fread 进去时,它会给我 3 条记录和 3 的计数。但是从那以后,无论我备份还是读入,它将给我相同的计数 3 和 3 记录,但由于计数未更新,这可能是 fread 仅读取第一次记录的原因。

我不确定为什么计数器没有更新。 freadfwrite 都返回 = 成功所以我不确定发生了什么。

void backUp(PAYROLL employee[], long int *pCounter)
{
    FILE *counter;
        errno_t result1 = fopen_s(&counter, "c:\myFiles\counter.bin", "a+b");
        if (result1 == 0){
            fwrite(pCounter, sizeof(long int), 1, counter);
            fclose(counter);
        }
        else
            printf("Back up of counter failed! error:%d",result1);

    FILE *record;

        errno_t result2 = fopen_s(&record, "c:\myFiles\record.bin", "a+b");
        if (result2 == 0){
            fwrite(employee, *pCounter *sizeof(PAYROLL), 1, record);
            fclose(record);
        }

        else
            printf("Back up of record failed! error:%d", result2);
}

void upload(PAYROLL employee[], long int *pCounter)
{
    FILE *counter;
    errno_t result1 = fopen_s(&counter, "c:\myFiles\counter.bin", "a+b");
    if (result1 == 0){
        result = fread(pCounter, sizeof(long int), 1, counter);
        fclose(counter);
        printf("Counter:%d", *pCounter);
    }
    else
        printf("Upload up of counter failed!");
    FILE *record;
    errno_t result2 = fopen_s(&record, "c:\myFiles\record.bin", "r+b");
    if (result2 == 0)
    {

            result2 = fread(employee, *pCounter *sizeof(PAYROLL), 1, record);
            printf("Upload successful!\n");

        fclose(record);
    }
    else
        printf("Error opening file!");
}

我看到你的程序有很多错误。

首先,您将长整数和 PAYROLL 结构直接写入文件。你永远不应该这样做,因为结构和整数具有依赖于机器的表示,如果你在一台机器(比如 32 位机器)上写入文件并在另一台机器(比如 64 位机器)上读取它们,那么你可能运行 遇到问题。

其次,您没有检查 fread() 的 return 值。应该经常检查。

第三,您将 fread() 的 return 值分配给 errno_t。您确定要这样做吗?

如果您想得到实际问题的答案,请考虑更新源代码以修复我指出的错误,并考虑改进您问题中的英语。此外,您应该提供一个完整的示例,即包含 PAYROLL 定义的示例。当您知道 fread() 的实际 return 值时,也许问题会更容易追踪。

将最突出的评论转化为答案。

Weathervane :

How do you know that fread and fwrite are returning "success" when you have not checked their return value?

Jude评论:

I look through the debugger and step in to the function, result is giving me their success return values (if that's how it works).

Weathervane :

You still need that in the program. Without that sort of checking, your code will be blown over by a puff of wind.

Dmitri correctly :

Looks like everywhere you open in append mode "a+b" you should probably be using something else ("rb" in upload() and "wb" in backUp() possibly?)

Jude评论:

I don't understand, is there a specific function for error checking? As I had always thought that error checking was just looking at what goes in the value of result and then I can go check what the value means?

查看 fread() 的规格和 fwrite()。它们 return 写入或读取的记录数,可能少于请求的数量。如果你得到一个短写,那么你就有问题了——可能是磁盘不足 space。如果您读取的内容很短,则可能是您请求了 100 条记录,但只有 1、10 或 99 条记录可供读取(或者出现错误)。如果您不捕获并检查 return 值,您将不知道发生了什么。

Jude评论:

I see they read and write 1, but it still stores the first 3 elements of my struct array. I assume it's one because it's only writing my array?

fread()(以及 fwrite() 也)为您提供了相当大的灵活性,因为您可以分别提供项目的大小和项目的数量。您使用:

result2 = fread(employee, *pCounter *sizeof(PAYROLL), 1, record);

这告诉 fread() 读取 1 个大小为 *pCounter * sizeof(PAYROLL) 的项目。您将得到 1(成功)或 0(失败)的结果。您可以指定:

result2 = fread(employee, sizeof(PAYROLL), *pCounter, record);

这会告诉您读取了多少条大小为 sizeof(PAYROLL) 的记录,最多为 *pCounter 中的最大值。您可能会得到 0 或 1 或……

这里有一些可行的代码,它们或多或少地完成了所需的工作。 main() 程序演示了处理 1、2 和 3 条记录(名字是英国的几位国王和王后,以及他们登基的年份作为他们的员工 ID 号)。我不得不创建一个最小的工资单结构,因为问题没有提供。

#include <stdio.h>
#include <string.h>
#include <errno.h>

typedef struct PAYROLL
{
    long emp_id;
    char emp_name[32];
} PAYROLL;

static const char counter_bin[] = "counter.bin";
static const char records_bin[] = "records.bin";

static
void backUp(PAYROLL employee[], long int *pCounter)
{
    FILE *counter = fopen(counter_bin, "wb");
    if (counter != 0){
        fwrite(pCounter, sizeof(long int), 1, counter);
        fclose(counter);
    }
    else
        fprintf(stderr, "Back up of counter failed! error: %d %s\n", errno, strerror(errno));

    FILE *record = fopen(records_bin, "wb");
    if (record != 0){
        fwrite(employee, *pCounter *sizeof(PAYROLL), 1, record);
        fclose(record);
    }
    else
        fprintf(stderr, "Back up of records failed! error: %d %s\n", errno, strerror(errno));
}

static
void upload(PAYROLL employee[], long int *pCounter)
{
    FILE *counter = fopen(counter_bin, "rb");
    if (counter != 0){
        size_t result = fread(pCounter, sizeof(long int), 1, counter);
        fclose(counter);
        if (result != 0)
            printf("Counter: %ld\n", *pCounter);
        else
            fprintf(stderr, "Failed to read counter\n");
    }
    else
        fprintf(stderr, "Upload up of counter failed!\n");

    FILE *record = fopen(records_bin, "r+b");
    if (record != 0)
    {
        size_t result2 = fread(employee, *pCounter * sizeof(PAYROLL), 1, record);
        if (result2 == 1)
            printf("Upload successful!\n");
        else
            fprintf(stderr, "Failed to read records!\n");
        fclose(record);
    }
    else
        fprintf(stderr, "Error opening file!");
}

int main(void)
{
    PAYROLL emps[] =
    {
        { 1066, "William the Conqueror" },
        { 1819, "Victoria" },
        { 1689, "William and Mary" },
    };

    for (int i = 1; i <= 3; i++)
    {
        long emp_count = i;
        printf("Employee count = %ld\n", emp_count);
        backUp(emps, &emp_count);
        upload(emps, &emp_count);
        for (int j = 0; j < emp_count; j++)
            printf("%4ld: %s\n", emps[j].emp_id, emps[j].emp_name);
    }

    return 0;
}

请注意,我已经分解出文件名,这样您只需更改一行即可更改使用的文件。示例输出:

$ Employee count = 1
Counter: 1
Upload successful!
1066: William the Conqueror
Employee count = 2
Counter: 2
Upload successful!
1066: William the Conqueror
1819: Victoria
Employee count = 3
Counter: 3
Upload successful!
1066: William the Conqueror
1819: Victoria
1689: William and Mary
$ odx counter.bin
0x0000: 03 00 00 00 00 00 00 00                           ........
0x0008:
$ odx records.bin
0x0000: 2A 04 00 00 00 00 00 00 57 69 6C 6C 69 61 6D 20   *.......William 
0x0010: 74 68 65 20 43 6F 6E 71 75 65 72 6F 72 00 00 00   the Conqueror...
0x0020: 00 00 00 00 00 00 00 00 1B 07 00 00 00 00 00 00   ................
0x0030: 56 69 63 74 6F 72 69 61 00 00 00 00 00 00 00 00   Victoria........
0x0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x0050: 99 06 00 00 00 00 00 00 57 69 6C 6C 69 61 6D 20   ........William 
0x0060: 61 6E 64 20 4D 61 72 79 00 00 00 00 00 00 00 00   and Mary........
0x0070: 00 00 00 00 00 00 00 00                           ........
0x0078:
$

odx 只是一个十六进制转储程序。选择你自己的程序来做同样的工作——od -c 是一个后备方案,虽然我不是特别喜欢它的格式。)