Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Fwrite不会复制二进制文件副本中的所有字节_C_File_Binaryfiles_Fwrite_Fread - Fatal编程技术网

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
    函数都可以用空文件指针调用,可能导致崩溃。您应该将它们移动到您知道每个已成功打开的作用域中
  • 引发这个问题的最大问题是,您没有处理文件大小不是
    BYTE\u size
    的偶数倍的情况。因为您为整个文件分配了足够的内存,所以您应该只读取和写入整个文件<代码>fread(buf,1,大小,src)
    fwrite(buf,1,大小,dst)。通常,最好将元素大小参数设置为
    fread/fwrite
    1,并计算要读取或写入的字节数。没有数学上的错误,你可以准确地知道读/写了多少字节
这是我已经更正和注释过的原始函数的一个版本,如果没有任何问题,它也可以工作

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

如果这是一个函数,我们可以自己尝试,但是不知道你所有的常量是什么,你没有展示的函数是什么,很难说。为什么你不只是读写
大小
?当
大小
不是
字节大小
的偶数倍时会发生什么?我注意到的第一件事是完整的缺少错误检查。你不会走得太远。也就是说,欢迎使用堆栈溢出!请使用