從一個(gè)文件中把數(shù)據(jù)復(fù)制到另外一個(gè)文件中,我的代碼如下: while (i<38016)//文件大小為38016字節(jié),i(unsigned int),temp(char) { fread(&temp,1,1,fyuv); fwrite(&temp,1,1,fyuv1); i++; } 結(jié)果文件有38k,其中前面大概10k是正確的(與源文件進(jìn)行二進(jìn)制代碼比對(duì)),后面的約28k就重復(fù)前面10k的最后一個(gè)字節(jié),也就是后面28k所有字節(jié)完全一樣。 若把代碼換成: do { i=fread(&temp,1,1,fyuv); fwrite(&temp,i,1,fyuv1); }while(i>0); 則得到的結(jié)果文件大概只有10k,且這10k與源文件的前10k一樣(比對(duì)二進(jìn)制代碼),但是后28k就沒有了。 請(qǐng)問我該怎么做才是正確的呢? 錯(cuò)誤原因: 你用文本方式打開了二進(jìn)制文件 文本方式讀取二進(jìn)制數(shù)據(jù), 可能在文件結(jié)束之前將某段數(shù)據(jù)判定為文件末尾EOF, 所以結(jié)束讀取( 舉個(gè)例子, 比如遇到 0x00 0x00 0xff 0xff, 則文本方式方式的文件流, 認(rèn)為已經(jīng)到文件末尾, 不能讀取) 你這個(gè)38016的文件, 大概在10k左右有段數(shù)據(jù)和文件結(jié)束標(biāo)志格式相同, 文本方式讀取到10k左右就認(rèn)為文件結(jié)束了( 真正的文本文件, 結(jié)束標(biāo)志可能在磁盤簇的剩余空間中 ) 所以第一種方式: 固 定讀取38016次, 每次往新文件中寫一個(gè)字節(jié); 前10k次能讀取到內(nèi)容, fread返回值是1, 這樣寫過去的一字節(jié)就是讀取的字節(jié); 后28k因?yàn)樽x取失敗, fread返回值為0, 這樣temp的內(nèi)容就不會(huì)被改寫, 仍然是最后一次成功讀取的值, 但因?yàn)槭菍懘螖?shù)固定, 所以后28k就重復(fù)寫過去; 后一種方式: 根據(jù)fread的返回值來判定文件結(jié)束, 這是正確的方法; 所以讀取到10k后, 返回值為0, 表示無效, 文件結(jié)束, 所以只復(fù)制了10k內(nèi)容 CFile只支持二進(jìn)讀寫, 所以你的結(jié)果是正確的( CFile用CFile::typeText格式會(huì)報(bào)錯(cuò); CStdioFile才能文本讀寫) 用fopen返回的FILE, 如果讀取的時(shí)候沒有加b( 比如"r"), 則默認(rèn)的是文本格式; 所以請(qǐng)用"rb"來讀取二進(jìn)制文件, 用"wb"寫二進(jìn)制文件; 當(dāng)然如果只是復(fù)制文件的話, 純二進(jìn)制讀寫沒有問題 下面是樓主要的效果, 是一個(gè)字節(jié)讀寫的 #include <stdio.h> int main() { FILE *pFileS = fopen( "s.rar", "rb" ); if( ! pFileS ) return 1; FILE *pFileD = fopen( "d.rar", "wb+" ); unsigned char bTemp; while( fread( &bTemp, sizeof(unsigned char), 1, pFileS) ) fwrite( &bTemp, sizeof(unsigned char), 1, pFileD ); fclose( pFileS ), fclose( pFileD ); return 0; } 其實(shí)一個(gè)字節(jié)讀寫的話, 用fgetc和fputc就可以了, 當(dāng)然還是得以二進(jìn)制方式打開 另外單字節(jié)讀寫速度太慢; 系統(tǒng)中復(fù)制文件都是整塊讀寫的, 設(shè)置緩沖大小 比如 #include <stdio.h> int main() { FILE *pFileS = fopen( "s.rar", "rb" ); if( ! pFileS ) return 1; FILE *pFileD = fopen( "d.rar", "wb" ); unsigned char buffer[ 4 * 1024 ]; int nRead; while( nRead = fread( buffer, sizeof(unsigned char), sizeof(buffer), pFileS ) ) fwrite( buffer, sizeof(unsigned char), nRead, pFileD ); fclose( pFileS ), fclose( pFileD ); return 0; } 另外, fread單次讀取的總字節(jié)數(shù)有限制, 也就是說緩沖有上限; 只能通過提高次數(shù)來讀取大文件; 在這方面, 用API如ReadFile或者調(diào)用了這些API的封裝類就好得多; 當(dāng)然, 次數(shù)多對(duì)電腦來說不是問題呵呵 附: 至于文本方式不能完全讀取, 而二進(jìn)制方式能的原因- 文 本方式讀取文件, 最主要的用處是一次讀取一整句( 以換行符'\n', 即二進(jìn)制的換行標(biāo)志"\r\n"結(jié)束 ), 方便用于特殊用處ReadString、fscanf(...,"%s",...)之類, 每次讀取的內(nèi)容長(zhǎng)度是不定的; 而二進(jìn)制讀取方式Read、fread等, 都是讀取固定長(zhǎng)度 所以文本方式讀取對(duì)EOF的判定, 是一個(gè)文件尾結(jié)束標(biāo)志, 如果是文本文件, 則這個(gè)文件尾肯定不會(huì)出現(xiàn)在文件內(nèi)容中( 因?yàn)槭遣豢纱蛴∽址麡?gòu)成的結(jié)束標(biāo)志, 人可讀的文本文件不會(huì)包括它 ), 這樣以結(jié)束標(biāo)志為文件尾則是可以的; 二進(jìn)制文件內(nèi)容可以是任意字節(jié), 如果把它當(dāng)文本文件來讀, 以文件尾為結(jié)束, 當(dāng)然可能出現(xiàn)把文件內(nèi)容判定為文件尾的情況; 二進(jìn)制讀取方式 由于每次讀取固定字節(jié), 所以只需要用總文件長(zhǎng)度( 這個(gè)數(shù)值是系統(tǒng)管理的數(shù)值, 不是計(jì)算得出來的 )減去每次讀取的長(zhǎng)度( 或根據(jù)Seek的位置計(jì)算長(zhǎng)度 ), 就可以知道是否到文件尾, 不需要定義結(jié)束標(biāo)志; 所以用二進(jìn)制方式打開任何文件都是合理的 |
|