fread() 和 fwrite() 可以用来复制 jpeg 吗?

Can fread() and fwrite() be used to copy jpegs?

我是编程新手,我正在尝试编写一个基本程序来复制 jpeg 文件:

#include <stdio.h>

int main (void)
{
    FILE *a = fopen("pic1.jpg", "r");
    
    FILE *b = fopen("pic2.jpg", "w");
    
    fread(a, 1, sizeof(a), b);
    fwrite(a, 1, sizeof(a), b);
    
    fclose(a);
    fclose(b);
}

该程序确实创建了一个新文件 pic2.jpg,但是,当我尝试查看它时,我收到错误消息:Invalid or Unsupported Image Format,所以这让我觉得我可能正在尝试错误使用此功能。

是的,但您没有正确使用它们。

fread(a, 1, sizeof(a), b) 表示从 b sizeof(a) 次读取 1 个字节到文件 *a 中。这编译,但没有多大意义。您在 fwrite.

中犯了类似的错误

sizeof(a) 获取 FILE * 指针的大小,通常为 8 个字节,而不是文件的大小。所以你只读写了 8 个字节。

freadfwrite 的第一个参数是一个用于读取和写入的缓冲区,这是缺少的关键元素。


首先,经常检查你的文件操作是否有效。如果他们失败了,如果文件不存在或无法打开,程序将继续愉快地运行,当它试图写入 NULL 时你会得到奇怪的错误。

一些系统区分“二进制”和“文本”文件。您必须添加 b 标志以确保它们不会破坏内容。

我还会使用更具描述性的名称,以免我们混淆。

FILE *in = fopen("pic1.jpg", "rb");
if( !in ) {
    perror("can't open pic1.jpg for reading");
}

FILE *out = fopen("pic2.jpg", "wb");
if( !out ) {
    perror("can't open pic2.jpg for writing");
}

现在我们需要分配一个缓冲区来读取和写入。为了获得最佳性能,这应该类似于磁盘的自然块大小。 4096 或 BUFSIZ 常数是不错的选择。我们使用 char 作为字节数组的替代项。如果你想花哨一点,你可以使用 uint8_t,但因为我们只是复制字节,所以没有实际区别。

循环读取并从中写入,直到读取所有内容。

char buf[BUFSIZ];
size_t bytes_read;

// Read a buffer sized hunk.
while( (bytes_read = fread(buf, 1, sizeof(buf), in)) ) {
    // Write the hunk, but only as much as was read.
    fwrite(buf, 1, bytes_read, out);
}

fclose(in);
fclose(out);

我们可以在这里使用sizeof(buf)只是因为buf是一个已知大小的数组。它将 return 缓冲区的大小,而不是 char * 指针的大小。

我们必须小心,只写和读一样多,而不是整个缓冲区。否则,如果我们 fwrite(buf, 1, sizeof(buf), out) 并且最后一次读取仅部分填充缓冲区,我们将打印垃圾。

fread returns 读取的“项目”数,而不是字节数。这是从很久以前开始的,当时文件更可能具有固定大小的记录。为了让它达到 return 字节数,我们告诉它每个“项目”是 1 个字节,我们想要 sizeof(buf) 个“项目”。