在 fwrite() 上循环 fread() 与单独使用它们有什么区别?
What is the difference between looping fread() over fwrite() vs using them separately?
(注意:向半小时前阅读我之前 post 的任何人道歉 - 我意识到我 post 输入了错误的一半代码,实际上是后半部分给我带来了问题。所以,如果这个 post 看起来很熟悉,那可能是!)
我正在尝试制作一个复制 .wav
文件的基本程序,这是我的尝试:
#include <stdio.h>
#include <stdint.h>
int main (void)
{
FILE* input = fopen("input.wav", "r");
FILE* output = fopen("output.wav", "w");
uint8_t header [44];
fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);
int16_t body;
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
fclose(input);
fclose(output);
}
然而,在未能使其工作之后,我查找了如何做,显然
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
应该是
while (fread(&body, sizeof(int16_t), 1, input))
{
fwrite(&body, sizeof(int16_t), 1, output);
}
为什么第一部分可以毫无问题地复制header,但第二部分必须使用循环才能工作?在我看来,他们似乎在做同样的事情。
看看读写函数。如您所见,这两个函数的签名非常相似并且使用相同的参数。两者都用于对 块 数据进行操作。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Argument
Description
*ptr
Points to the buffer where the data is stored
size
The size of each block in bytes
nmemb
The amount of blocks to read/write
*stream
Points to the structure which describes the outgoing stream
因此,您的代码的不同之处在于:
// will read ONE block of data with the size of int16_t
fread(&body, sizeof(int16_t), 1, input);
// will read 44 blocks of data with the size of uint8_t
fread(header, sizeof(uint8_t), 44, input);
// will write ONE block of data with the size of int16_t
fwrite(&body, sizeof(int16_t), 1, output);
// will write 44 blocks of data with the size of int16_t
fwrite(header, sizeof(uint8_t), 44, output);
两种方法return size_t
类型的值,反映读取或写入的字节数。如果他们 return 0,则什么也没有发生。如您所知,不等于 0 的所有内容在 C 中都被认为是真实的。所以回答您的问题:
// reads ONE Block of size int16_t at a time and stores it in body
// => will return 0 and stop the loop if nothing was read anymore
while (fread(&body, sizeof(int16_t), 1, input))
{
// writes ONE block of size int16_t from body to output
fwrite(&body, sizeof(int16_t), 1, output);
}
只要还有数据要读取,循环就会继续,然后停止。文件的 header 具有固定大小,因为它是标准化的。文件的其余部分具有可变长度,因此循环。
我认为这里的根本问题是你读写 header 的代码是一次读取 44 字节的 header,而读写 body 只读和写两个字节。但是wav文件的body大概比两个字节大很多!
具体来说,这段代码:
fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);
一次读取和写入一个 44 字节 header。但是这段代码:
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
读写两个字节。如果 body 只是两个字节长,那很好。但如果不是,它不会复制整个 body;它只会复制前两个字节。
另一方面,此代码读取和写入多个 two-byte objects,其中有多少:
while (fread(&body, sizeof(int16_t), 1, input) == 1)
fwrite(&body, sizeof(int16_t), 1, output);
如果您知道 body 有多大,您也可以一次读取和写入所有内容(也就是说,就像您对 header 所做的那样):
uint8_t body[body_size];
fread(body, 1, body_size, input);
fwrite(body, 1, body_size, output);
或者,如果您知道 body 大小为 16 位字,并且您想要那样考虑,您可以
uint16_t body [body_size_in_words];
fread(body, 2, body_size_in_words, input);
fwrite(body, 2, body_size_in_words, output);
fread
和 fwrite
可能会造成混淆,因为它们旨在让您假装您正在读取和写入的不是单个字节。可以通过三种不同的方式使用它们:
fread(buf, 1, n, fp)
读取 n
字节
fread(buf, size, 1, fp)
读取一条 size
字节的记录
fread(buf, size, n, fp)
读取 n
条 size
字节的记录
在深处,fread
基本上只是乘以 n * size
,并尝试读取那么多字节。然后,无论它读取多少字节,它都会将该数字除以 size
,然后返回给您——也就是说,它 returns 读取的记录数,不一定是读取的字节数。当然,同样的例子、解释和论点也适用于 fwrite
。
(注意:向半小时前阅读我之前 post 的任何人道歉 - 我意识到我 post 输入了错误的一半代码,实际上是后半部分给我带来了问题。所以,如果这个 post 看起来很熟悉,那可能是!)
我正在尝试制作一个复制 .wav
文件的基本程序,这是我的尝试:
#include <stdio.h>
#include <stdint.h>
int main (void)
{
FILE* input = fopen("input.wav", "r");
FILE* output = fopen("output.wav", "w");
uint8_t header [44];
fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);
int16_t body;
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
fclose(input);
fclose(output);
}
然而,在未能使其工作之后,我查找了如何做,显然
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
应该是
while (fread(&body, sizeof(int16_t), 1, input))
{
fwrite(&body, sizeof(int16_t), 1, output);
}
为什么第一部分可以毫无问题地复制header,但第二部分必须使用循环才能工作?在我看来,他们似乎在做同样的事情。
看看读写函数。如您所见,这两个函数的签名非常相似并且使用相同的参数。两者都用于对 块 数据进行操作。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Argument | Description |
---|---|
*ptr | Points to the buffer where the data is stored |
size | The size of each block in bytes |
nmemb | The amount of blocks to read/write |
*stream | Points to the structure which describes the outgoing stream |
因此,您的代码的不同之处在于:
// will read ONE block of data with the size of int16_t
fread(&body, sizeof(int16_t), 1, input);
// will read 44 blocks of data with the size of uint8_t
fread(header, sizeof(uint8_t), 44, input);
// will write ONE block of data with the size of int16_t
fwrite(&body, sizeof(int16_t), 1, output);
// will write 44 blocks of data with the size of int16_t
fwrite(header, sizeof(uint8_t), 44, output);
两种方法return size_t
类型的值,反映读取或写入的字节数。如果他们 return 0,则什么也没有发生。如您所知,不等于 0 的所有内容在 C 中都被认为是真实的。所以回答您的问题:
// reads ONE Block of size int16_t at a time and stores it in body
// => will return 0 and stop the loop if nothing was read anymore
while (fread(&body, sizeof(int16_t), 1, input))
{
// writes ONE block of size int16_t from body to output
fwrite(&body, sizeof(int16_t), 1, output);
}
只要还有数据要读取,循环就会继续,然后停止。文件的 header 具有固定大小,因为它是标准化的。文件的其余部分具有可变长度,因此循环。
我认为这里的根本问题是你读写 header 的代码是一次读取 44 字节的 header,而读写 body 只读和写两个字节。但是wav文件的body大概比两个字节大很多!
具体来说,这段代码:
fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);
一次读取和写入一个 44 字节 header。但是这段代码:
fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);
读写两个字节。如果 body 只是两个字节长,那很好。但如果不是,它不会复制整个 body;它只会复制前两个字节。
另一方面,此代码读取和写入多个 two-byte objects,其中有多少:
while (fread(&body, sizeof(int16_t), 1, input) == 1)
fwrite(&body, sizeof(int16_t), 1, output);
如果您知道 body 有多大,您也可以一次读取和写入所有内容(也就是说,就像您对 header 所做的那样):
uint8_t body[body_size];
fread(body, 1, body_size, input);
fwrite(body, 1, body_size, output);
或者,如果您知道 body 大小为 16 位字,并且您想要那样考虑,您可以
uint16_t body [body_size_in_words];
fread(body, 2, body_size_in_words, input);
fwrite(body, 2, body_size_in_words, output);
fread
和 fwrite
可能会造成混淆,因为它们旨在让您假装您正在读取和写入的不是单个字节。可以通过三种不同的方式使用它们:
fread(buf, 1, n, fp)
读取n
字节fread(buf, size, 1, fp)
读取一条size
字节的记录fread(buf, size, n, fp)
读取n
条size
字节的记录
在深处,fread
基本上只是乘以 n * size
,并尝试读取那么多字节。然后,无论它读取多少字节,它都会将该数字除以 size
,然后返回给您——也就是说,它 returns 读取的记录数,不一定是读取的字节数。当然,同样的例子、解释和论点也适用于 fwrite
。