C Fwrite不会复制二进制文件副本中的所有字节
我正在尝试将二进制文件从C Fwrite不会复制二进制文件副本中的所有字节,c,file,binaryfiles,fwrite,fread,C,File,Binaryfiles,Fwrite,Fread,我正在尝试将二进制文件从src复制到dst。此脚本似乎复制了所有字节。但当我在Hex Workshop中打开这两个文件时,我发现dst文件的末尾总是缺少3个字节。这3个字节应该是00,此问题阻止我打开dst文件 void binaryCopy(char **argv) { int *buf = 0; int elements = 0; int size = 0, wantOverwrite = 0; FILE *src = fopen(argv[SRC_POS],
src
复制到dst
。此脚本似乎复制了所有字节。但当我在Hex Workshop中打开这两个文件时,我发现dst
文件的末尾总是缺少3个字节。这3个字节应该是00
,此问题阻止我打开dst
文件
void binaryCopy(char **argv) {
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(argv[SRC_POS], "rb");
FILE *dst = fopen(argv[DST_POS], "w+b");
if (src) {
if (dst) {
wantOverwrite = overwrite();
}
if (wantOverwrite) {
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
buf = (int *)malloc(size);
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
printf("copy completed");
free(buf);
}
}
fclose(dst);
fclose(src);
}
您编写的函数中存在几个问题
fopen(文件名,“w+b”)代码>截断文件,因此以后的覆盖检查没有意义
- 您没有在malloc之后检查NULL,您的缓冲区应该是一个
,因为无符号字符*
会将其解释为fread/fwrite
- 最后,两个
函数都可以用空文件指针调用,可能导致崩溃。您应该将它们移动到您知道每个已成功打开的作用域中fclose
- 引发这个问题的最大问题是,您没有处理文件大小不是
的偶数倍的情况。因为您为整个文件分配了足够的内存,所以您应该只读取和写入整个文件<代码>fread(buf,1,大小,src)代码>和BYTE\u size
fwrite(buf,1,大小,dst)代码>。通常,最好将元素大小参数设置为
1,并计算要读取或写入的字节数。没有数学上的错误,你可以准确地知道读/写了多少字节fread/fwrite
void originalBinaryCopy(const char *srcFilename, const char *dstFilename)
{
//odd size to ensure remainder
const size_t BYTE_SIZE = 777;
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(srcFilename, "rb");
//This truncates dst, so the overwirte check is meaningless
FILE *dst = fopen(dstFilename, "w+b");
if (src)
{
if (dst)
{
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
//always check for NULL after malloc - This should be a char*
buf = (int *)malloc(size);
if (!buf)
{
fclose(dst);
fclose(src);
return;
}
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
//added, copy remainder
elements = fread(buf, 1, size % BYTE_SIZE, src);
fwrite(buf, 1, size % BYTE_SIZE, dst);
//end
printf("copy completed %s -> %s\n", srcFilename, dstFilename);
free(buf);
}
}
//dst could be NULL here, move inside if(dst) scope above
fclose(dst);
//src could be NULL here, move inside if(src) scope above
fclose(src);
if (comp(srcFilename, dstFilename) != 0)
{
printf("compare failed - %s -> %s\n", srcFilename, dstFilename);
}
}
请注意在最后如何处理剩余部分
下面是我将如何处理复制文件以及测试套件,以创建、复制和验证一组文件。它显示了如果您不想截断目标,并且在实际函数中有相当多的错误检查,如何避免截断目标。我没有在调用端包含任何特定的错误检查,但对于实际代码,我会列举所有可能的错误,并使用这些返回值传递给错误处理函数,该函数可以打印出这些错误并可能退出程序
操作文件是一件你需要非常小心的事情,因为如果你的代码不工作,可能会丢失数据,所以在你将它用于真实文件之前,请确保它在测试文件中是100%可靠的
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TEST_FILE_MIN 1024
#define TEST_FILE_MAX 1024 * 1024
const char *src_pattern = "src_file_%08x.bin";
const char *dst_pattern = "dst_file_%08x.bin";
void createTestFiles(const char *pattern)
{
char filename[256] = { 0 };
char buffer[1024];
for (size_t i = 0; i < sizeof(buffer); ++i)
{
buffer[i] = rand();
}
for (size_t i = TEST_FILE_MIN; i <= TEST_FILE_MAX; i *= 2)
{
sprintf(filename, pattern, i);
FILE *dst = fopen(filename, "wb");
if (dst)
{
size_t reps = i / TEST_FILE_MIN;
for (size_t w = 0; w < reps; ++w)
{
fwrite(buffer, 1, sizeof(buffer), dst);
}
fclose(dst);
}
}
}
int comp(const char *srcFilename, const char *dstFilename)
{
FILE *src = fopen(srcFilename, "rb");
if (!src)
{
return -1;
}
//open for reading to check for existence
FILE *dst = fopen(dstFilename, "rb");
if (!dst)
{
fclose(src);
return -2;
}
fseek(src, 0, SEEK_END);
size_t srcSize = ftell(src);
fseek(src, 0, SEEK_SET);
fseek(dst, 0, SEEK_END);
size_t dstSize = ftell(dst);
fseek(dst, 0, SEEK_SET);
if (srcSize == 0 || dstSize == 0 || srcSize != dstSize)
{
fclose(src);
fclose(dst);
return -3;
}
unsigned char *srcBuf = (unsigned char *)calloc(1, srcSize);
unsigned char *dstBuf = (unsigned char *)calloc(1, srcSize);
if (!srcBuf || !dstBuf)
{
fclose(src);
fclose(dst);
return -4;
}
if (fread(srcBuf, 1, srcSize, src) != srcSize)
{
fclose(src);
fclose(dst);
return -5;
}
if (fread(dstBuf, 1, dstSize, dst) != dstSize)
{
fclose(src);
fclose(dst);
return -6;
}
fclose(src);
fclose(dst);
//result * 100 to make this error outside te range of the other general errors from this function.
int result = memcmp(srcBuf, dstBuf, srcSize) * 100;
free(srcBuf);
free(dstBuf);
return result;
}
void originalBinaryCopy(const char *srcFilename, const char *dstFilename)
{
//odd size to ensure remainder
const size_t BYTE_SIZE = 777;
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(srcFilename, "rb");
//This truncates dst, so the overwirte check is meaningless
FILE *dst = fopen(dstFilename, "w+b");
if (src)
{
if (dst)
{
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
//always check for NULL after malloc - This should be a char*
buf = (int *)malloc(size);
if (!buf)
{
fclose(dst);
fclose(src);
return;
}
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
//added, copy remainder
elements = fread(buf, 1, size % BYTE_SIZE, src);
fwrite(buf, 1, size % BYTE_SIZE, dst);
//end
printf("copy completed %s -> %s\n", srcFilename, dstFilename);
free(buf);
}
}
//dst could be NULL here, move inside if(dst) scope above
fclose(dst);
//src could be NULL here, move inside if(src) scope above
fclose(src);
if (comp(srcFilename, dstFilename) != 0)
{
printf("compare failed - %s -> %s\n", srcFilename, dstFilename);
}
}
int binaryCopy(const char *srcFilename, const char *dstFilename, bool overwrite)
{
//arbitrary odd size so we can make sure we handle a partial buffer.
//assuming the code tests successfully I'd use something like 64 * 1024.
unsigned char buffer[7777] = { 0 };
FILE *src = fopen(srcFilename, "rb");
if (!src)
{
//Error, source file could not be opened
return -1;
}
//open for reading to check for existence
FILE *dst = fopen(dstFilename, "rb");
if (dst)
{
if (!overwrite)
{
//Error, dest file exists and we can't overwrite it
fclose(src);
fclose(dst);
return -2;
}
//reopen dst it for writing
if (!freopen(dstFilename, "wb", dst))
{
fclose(src);
fclose(dst);
dst = NULL;
}
}
else
{
//it didn't exist, create it.
dst = fopen(dstFilename, "wb");
}
if (!dst)
{
//Error, dest file couldn't be opened
fclose(src);
return -3;
}
//Get the size of the source file for comparison with what we read and write.
fseek(src, 0, SEEK_END);
size_t srcSize = ftell(src);
fseek(src, 0, SEEK_SET);
size_t totalRead = 0;
size_t totalWritten = 0;
size_t bytesRead = 0;
while (bytesRead = fread(buffer, 1, sizeof(buffer), src))
{
totalRead += bytesRead;
totalWritten += fwrite(buffer, 1, bytesRead, dst);
}
fclose(dst);
fclose(src);
if (totalRead != srcSize)
{
//src read error
return -4;
}
if (totalWritten != srcSize)
{
//dst write error
return -5;
}
return 0;
}
int main()
{
srand((unsigned)time(0));
createTestFiles(src_pattern);
for (size_t i = TEST_FILE_MIN; i <= TEST_FILE_MAX; i *= 2)
{
char srcName[256];
char dstName[256];
sprintf(srcName, src_pattern, i);
sprintf(dstName, dst_pattern, i);
//use my copy to create dest file
if (binaryCopy(srcName, dstName, true) != 0)
{
printf("File: '%s' failed initial copy.", srcName);
}
originalBinaryCopy(srcName, dstName);
if (binaryCopy(srcName, dstName, true) != 0)
{
printf("File: '%s' failed overwrite copy.", srcName);
}
if (binaryCopy(srcName, dstName, false) == 0)
{
printf("File: '%s' succeeded when file exists and overwrite was not set.", srcName);
}
//If compare succeeds delete the files, otherwise leave them for external comparison and print an error.
if (comp(srcName, dstName) == 0)
{
if (remove(srcName) != 0)
{
perror("Could not remove src.");
}
if (remove(dstName) != 0)
{
perror("Could not remove dst.");
}
}
else
{
printf("File: '%s' did not compare equal to '%s'.", srcName, dstName);
}
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#定义测试文件\u MIN 1024
#定义测试文件\u MAX 1024*1024
const char*src_pattern=“src_file_u%08x.bin”;
const char*dst_pattern=“dst_文件_u%08x.bin”;
void createTestFiles(常量字符*模式)
{
字符文件名[256]={0};
字符缓冲区[1024];
对于(大小i=0;i 对于(size_t i=TEST_FILE_MIN;i您观察到的最可能的原因是文件大小不是BYTE_size
的倍数:fread(buf,BYTE_size,size/BYTE_size,src);
读取的是BYTE_size
的倍数,fwrite
调用写入读取的字节
如果BYTE\u SIZE
是4
,类型int*buf=0;
似乎表明了这一点,并且如果源文件比4的倍数多3个字节,您的观察结果将得到充分解释
通过将buf
设置为unsigned char*
并将代码更改为:
elements = fread(buf, 1, size , src);
fwrite(buf, 1, elements, dst);
还请注意,不需要在更新模式下打开文件(模式字符串中的+
),错误和未明确处理,并且fclose()
调用放错了位置
如果overwrite()
返回0,则截断目标文件似乎也不正确
以下是具有更好错误处理能力的更正版本:
#包括
#包括
#包括
int二进制复制(char*argv[]{
文件*src,*dst;
长文件大小;
大小、读取大小、写入大小;
int想要重写;
无符号字符*buf;
if((src=fopen(argv[src_POS],“rb”))==NULL){
printf(“无法打开输入文件%s:%s\n”,argv[SRC_POS],strerror(errno));
返回-1;
}
wantOverwrite=覆盖();
如果(!wantOverwrite){
fclose(src);
返回0;
}
如果((dst=fopen(argv[dst_POS],“wb”))==NULL){
printf(“无法打开输出文件%s:%s\n”,argv[DST_POS],strerror(errno));
fclose(src);
返回-1;
}
fseek(src,0L,SEEK_END);
文件大小=ftell(src);
fseek(src,0L,SEEK_SET);
size=(size\u t)文件大小;
如果((长)大小!=文件大小){
printf(“文件大小对于单个块来说太大:%ld\n”,文件大小);
fclose(src);
fclose(dst);
返回-1;
}
buf=malloc(尺寸);
如果(buf==NULL){
printf(“无法分配%zu字节的块,\n”,大小);
fclose(src);
fclose(dst);
返回-1;
}
尺寸=fread(buf,1,尺寸,src);
如果(大小读取!=大小){
printf(“读取错误:%zu字节从%zu\n中读取”,大小\u读取,大小);
}
写入的大小=写入(buf,1,读取的大小,dst);
如果(写入大小!=读取大小){
printf(“写入错误:%zu字节写入%zu\n”,写入大小,读取大小);
}
如果(写入的大小==大小){
printf(“复制完成\n”);
}
免费(buf);
fclose(dst);
fclose(src);
返回0;
}
如果这是一个函数,我们可以自己尝试,但是不知道你所有的常量是什么,你没有展示的函数是什么,很难说。为什么你不只是读写大小?当大小不是字节大小的偶数倍时会发生什么?我注意到的第一件事是完整的缺少错误检查。你不会走得太远。也就是说,欢迎使用堆栈溢出!请使用