fwrite / fread 返回值的陷阱【C】(ze)

fwrite / fread 返回值的陷阱

fwrite / fread函数返回值的陷阱

二进制文件没有\n / EOF / len-1 作为读出的结束标识,fread 依靠读出块多少来标识读结果和文件结束标志。
以最小的单元格式进行读,或是以写入的最小单元进行读

我们通过文本进行写入:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
    int buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwirte((void *)buf,1,8,pf);
    fclose(pf);
    return 0;
}

执行结果为:
在这里插入图片描述

我们可以看到写入成功。
如果我们换一种,让块的大小为8一次性写入。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    fclose(pf);
    return 0;
}

执行结果为:
在这里插入图片描述

也没有问题。
但是在读的时候由很大的区别。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
    int n;    
    n = fread((void *)read,1,8,pf);   //n表示读取到完整块的个数
    printf("n = %d\n",n);
    n = fread((void*)read, 1,8, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    fclose(pf);
    return 0;
}

执行结果为:

在这里插入图片描述

我们可以看到,第一个n返回为8,一共读取了8次,每一次块的大小为1,所以返回的n完整的块个数为8个。当读取8块之后,文件位置到了结束位置,所以再读取的时候为0。

我们再把块的大小设置为8:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
    int n;    
    n = fread((void *)read,8,1,pf);   //n表示读取到完整块的个数
    printf("n = %d\n",n);
    n = fread((void*)read, 8,1, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    fclose(pf);
    return 0;
}

执行结果为:

在这里插入图片描述

我们看到一次8个字符全部被读取,所以刚好一个完整的块读取完。

那如果我再把块的大小设置为7:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
    int n;    
    n = fread((void*)read, 7, 1, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    n = fread((void*)read, 7, 1, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    fclose(pf);
    return 0;
}

执行结果为:
在这里插入图片描述
这就意味这第一次读取到了1234567,没有读取完,所以下一次再读取的时候还需要读7个。这里肯定是读取两次,但是第二次的返回结果为0,但是在一般情况下返回值只有在大于0的时候我们才关系,等于0的时候表示结束。

我们再把块的大小设置为3,我们现在让返回值打印三次,因为两次只能读取6个字节:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
    int n;    

    printf("n = %d\n", n);
    n = fread((void*)read, 3, 1, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    n = fread((void*)read, 3, 1, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    fclose(pf);
    return 0;
}

执行结果为:
在这里插入图片描述
我们可以看到前两次返回值为1,总共读取了6个字节,没有读取完需要再读取一次,返回值为0,因为6个字节读取完之后剩下两个字节,两个字节不能构成块。

所以我们在这只的时候要把块的大小设置为单元的块,我们这里一个字节设置一个块, 然后每次读取3个就没有问题。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
    int n;    
   
    n = fread((void*)read, 1, 3, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    n = fread((void*)read, 1, 3, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    n = fread((void*)read, 1, 3, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    n = fread((void*)read, 1, 3, pf);   //n表示读取到完整块的个数
    printf("n = %d\n", n);
    fclose(pf);
    return 0;
}

我们打印4次,执行结果为:
在这里插入图片描述

我们可以看到读取到了8个字节,后面再读取的时候为空。

那我们就可以把打印过程写成循环形式:

 #define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char buf[1024] = {"12345678"};
    FILE* pf= fopen("oo.txt","w+");
    if (pf == NULL)
        exit(-1);
    fwrite((void *)buf,8,1,pf);
    rewind(pf);
    char read[10];
int n;    
    while ((n = fread((void*)read, 1, 3, pf)) > 0)
    {
        for (int i = 0; i < n; i++)
        {
            printf("%c",read[i]);
        }
    }
    fclose(pf);
    return 0;
}

执行结果为:
在这里插入图片描述

文件里面的数据全部读取并打印出来。

我们说以块的大小问单元但是并不是说都是以1个字节,上面的代码由于我们写进去的数据为char类型,所以在读取的时候以字节为单元。如果我们定义int类型数据那么就以int类型4个字节为单元进行数据读取。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

int main()
{
    FILE* pf = fopen("qq.txt","w+");
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    fwrite((int*)arr,10,4,pf);
    int n = 0;
    rewind(pf);

    while ((n = fread((int*)arr, 4, 10, pf)) > 0)
    {
        for (int i = 0; i < n; i++)
        {
            printf("%d\t",arr[i]);
        }
    }
    return 0;
}

执行结果为:

在这里插入图片描述

小结

至此我们已经把fwrite / fread 返回值的陷阱已经详细说明,过程比较详细,读者可以多次阅读来不断理解。

发布了84 篇原创文章 · 获赞 71 · 访问量 9101

猜你喜欢

转载自blog.csdn.net/qq_43648751/article/details/104189207