簡體   English   中英

在 fwrite() 上循環 fread() 與單獨使用它們有什么區別?

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

(注:向半小時前閱讀我上一篇文章的任何人道歉——我意識到我發布了錯誤的一半代碼,實際上是后半部分給我帶來了問題。所以,如果這篇文章看起來可能是熟悉的!)

我正在嘗試制作一個復制.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,但第二部分必須使用循環才能工作? 在我看來,他們似乎在做同樣的事情。

我認為這里的根本問題是,您用於讀取和寫入 header 的代碼一次讀取 44 字節 header,而用於讀取和寫入正文的代碼僅讀取和寫入兩個字節。 但是 wav 文件的主體可能比兩個字節大得多!

具體來說,這段代碼:

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

讀取和寫入兩個字節。 如果正文只有兩個字節長,那很好。 但如果不是,它就不會復制整個身體; 它只是復制前兩個字節。

另一方面,這段代碼讀取和寫入多個兩字節對象,其中有多少:

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

如果您知道正文有多大,您可以一次讀取和寫入所有內容(也就是說,就像您對標題所做的那樣):

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

或者,如果您知道正文大小為 16 位字,並且您想這樣考慮,您可以這樣做

uint16_t body [body_size_in_words];
fread(body, 2, body_size_in_words, input);
fwrite(body, 2, body_size_in_words, output);

freadfwrite可能會令人困惑,因為它們旨在讓您假裝您正在讀取和寫入除單個字節之外的其他內容。 有三種不同的方式來使用它們:

  • fread(buf, 1, n, fp)讀取n個字節
  • fread(buf, size, 1, fp)讀取一條size字節的記錄
  • fread(buf, size, n, fp)讀取nsize字節的記錄

在內心深處, fread基本上只是乘以n * size ,並嘗試讀取那么多字節。 然后,無論它讀取多少字節,它都會在返回給您之前將該數字除以size - 也就是說,它返回讀取的記錄數,而不一定是讀取的字節數。 當然,同樣的例子、解釋和 arguments 也適用於fwrite

看看讀和寫函數。 如您所見,這兩個函數的簽名非常相似,並且使用相同的 arguments。 兩者都用於對數據進行操作。

 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);
爭論 描述
*指針 指向存儲數據的緩沖區
尺寸 每個塊的大小(以字節為單位)
納米粒 要讀/寫的塊數
*溪流 指向描述傳出 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);

這兩種方法都返回一個size_t類型的值,它反映了讀取或寫入的字節數。 如果他們返回 0,則什么都沒有發生。 如您所知,在 C 中,不等於 0 的所有內容都被認為是正確的。 所以回答你的問題:

// 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 具有固定大小,因為它是標准化的。 文件的 rest 具有可變長度,因此是循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM