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 个字节。
fread
和 fwrite
的第一个参数是一个用于读取和写入的缓冲区,这是缺少的关键元素。
首先,经常检查你的文件操作是否有效。如果他们失败了,如果文件不存在或无法打开,程序将继续愉快地运行,当它试图写入 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)
个“项目”。
我是编程新手,我正在尝试编写一个基本程序来复制 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 个字节。
fread
和 fwrite
的第一个参数是一个用于读取和写入的缓冲区,这是缺少的关键元素。
首先,经常检查你的文件操作是否有效。如果他们失败了,如果文件不存在或无法打开,程序将继续愉快地运行,当它试图写入 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)
个“项目”。