简体   繁体   English

在 fwrite() 上循环 fread() 与单独使用它们有什么区别?

[英]What is the difference between looping fread() over fwrite() vs using them separately?

(Note: Apologies to anyone who read my previous post from half an hour ago- I've realised that I posted the wrong half of the code, and it was actually the second half that was giving me problems. So, if this post seems familiar it probably is!) (注:向半小时前阅读我上一篇文章的任何人道歉——我意识到我发布了错误的一半代码,实际上是后半部分给我带来了问题。所以,如果这篇文章看起来可能是熟悉的!)

I'm trying to make a basic program which copies a .wav file, this was my attempt:我正在尝试制作一个复制.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);
}

However, after failing to make it work, I looked up how to do it and apparently但是,在未能使其工作之后,我查找了如何做到这一点,显然

fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);

should be应该

while (fread(&body, sizeof(int16_t), 1, input))
{
    fwrite(&body, sizeof(int16_t), 1, output);
}

Why is it that the first part can copy the header without a problem, but the second part has to use a loop in order to work?为什么第一部分可以毫无问题地复制header,但第二部分必须使用循环才能工作? To my eyes, they appear to be doing the same thing.在我看来,他们似乎在做同样的事情。

I think the fundamental issue here is that your code for reading and writing the header is reading the 44-byte header all at once, whereas the code for reading and writing the body is reading and writing just two bytes.我认为这里的根本问题是,您用于读取和写入 header 的代码一次读取 44 字节 header,而用于读取和写入正文的代码仅读取和写入两个字节。 But the body of the wav file is probably much bigger than two bytes!但是 wav 文件的主体可能比两个字节大得多!

Specifically, this code:具体来说,这段代码:

fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);

reads and writes a 44-byte header, all at once.一次读取和写入一个 44 字节的 header。 But this code:但是这段代码:

fread(&body, sizeof(int16_t), 1, input);
fwrite(&body, sizeof(int16_t), 1, output);

reads and writes two bytes.读取和写入两个字节。 If the body is just two bytes long, that's fine.如果正文只有两个字节长,那很好。 But if not, it's not going to copy the entire body;但如果不是,它就不会复制整个身体; it's just going to copy the first two bytes.它只是复制前两个字节。

This code, on the other hand, reads and writes multiple two-byte objects, as many of them as there are:另一方面,这段代码读取和写入多个两字节对象,其中有多少:

while (fread(&body, sizeof(int16_t), 1, input) == 1)
    fwrite(&body, sizeof(int16_t), 1, output);

If you knew how big the body was, you could read and write it all at once, also (that is, just like you did with the header):如果您知道正文有多大,您可以一次读取和写入所有内容(也就是说,就像您对标题所做的那样):

uint8_t body[body_size];
fread(body, 1, body_size, input);
fwrite(body, 1, body_size, output);

Or, if you know the body size as 16-bit words, and you want to think about it that way, you could do或者,如果您知道正文大小为 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 and fwrite can be confusing because they're designed to let you pretend you're reading and writing something other than individual bytes. freadfwrite可能会令人困惑,因为它们旨在让您假装您正在读取和写入除单个字节之外的其他内容。 There are sort of three different ways to use them:有三种不同的方式来使用它们:

  • fread(buf, 1, n, fp) read n bytes fread(buf, 1, n, fp)读取n个字节
  • fread(buf, size, 1, fp) read one record of size bytes fread(buf, size, 1, fp)读取一条size字节的记录
  • fread(buf, size, n, fp) read n records of size bytes fread(buf, size, n, fp)读取nsize字节的记录

Deep down, fread basically just multiplies n * size , and tries to read that many bytes.在内心深处, fread基本上只是乘以n * size ,并尝试读取那么多字节。 Then, however many bytes it reads, it divides that number by size before returning it to you -- that is, it returns the number of records read, not necessarily the number of bytes read.然后,无论它读取多少字节,它都会在返回给您之前将该数字除以size - 也就是说,它返回读取的记录数,而不一定是读取的字节数。 And the same examples, explanations, and arguments hold for fwrite , of course.当然,同样的例子、解释和 arguments 也适用于fwrite

Have a look at the read and write functions.看看读和写函数。 As you can see, the signatures of both functions are very similiar and use the same arguments.如您所见,这两个函数的签名非常相似,并且使用相同的 arguments。 Both are used to operate on blocks of data.两者都用于对数据进行操作。

 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指向描述传出 stream 的结构

So, the difference in your code is:因此,您的代码的区别是:

// 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);

Both methods return a value of type size_t that reflects the amount of bytes which were read or wrote.这两种方法都返回一个size_t类型的值,它反映了读取或写入的字节数。 If they return 0, nothing happened.如果他们返回 0,则什么都没有发生。 As you know everything unequal to 0 is considered to be true in C.如您所知,在 C 中,不等于 0 的所有内容都被认为是正确的。 So to answer your question:所以回答你的问题:

// 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);
}

The loop will continue as long as there is data left to read, then stop.只要还有数据要读取,循环就会继续,然后停止。 The header of the file has a fixed size, as it is standardized.文件的 header 具有固定大小,因为它是标准化的。 The rest of the file has a variable length, hence the loop.文件的 rest 具有可变长度,因此是循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM