-3

我正在尝试打开并读取 4 MB 的 bin 文件,但无法fread读取超过 ~700 KB 的内容。实际上我想打开并读取 genesis ROM 文件,它是二进制格式,读取应该从开始到最后一个字节。当尝试读取该数量时,运行时会发生错误,程序停止并关闭。

我的代码:

#include <stdio.h>
int main ()
{
    FILE* fp;
    int buffer[4000000];
    fp=fopen ("file.bin","rb");
    fread (buffer,sizeof(int),4000000,fp);
}

我的代码有什么问题?

4

5 回答 5

3

请在循环中针对特定的块大小执行读取操作。

于 2013-04-25T08:14:41.943 回答
1

[1] 缺少返回(返回负数表示发生错误)

[2] 使用malloc(动态分配堆外)而不是堆栈

[3] 检查文件读取、内存分配和读取字节数的指针值

#include <stdio.h>
#include <stdlib.h>

int main ()
{
    FILE * pFile;
    char * buffer;
    size_t size = 4194304;
    size_t result;

    pFile = fopen ( "file.bin" , "rb" );
    if (pFile==NULL) {
       fputs ("Unable to open file",stderr); 
       return (-1);
    }

    buffer = (char*) malloc (sizeof(char)*size);
    if (buffer == NULL) {
        fputs ("Unable to allocate memory",stderr); 
        return (-2);
    }

    result = fread (buffer,1,size,pFile);
    if (result != size) {
       fputs ("Unable to read 4 MB",stderr); 
       return (-3);
    }

    fclose (pFile);
    free (buffer);
    return 0;
}
于 2013-04-25T08:28:19.080 回答
0

更好的选择是加载文件我的块。

另外为了不耗尽堆栈,您应该使用动态分配的缓冲区,因为heap它大于stack.

#define BLOCK_SIZE 4096

#include <stdio.h>
#include <stdlib.h>

int read_file(FILE* file, unsigned char* buffer);

int main ()
{
     FILE* fp;
     unsigned char* buffer = NULL;
     int bytes_read = 0;
     fp=fopen ("file.bin","rb");
     bytes_read = read_file(fp, buffer);
     return 0;
}

int read_file(FILE* file, unsigned char* buffer)
{
    int bytes_read = 0;
    int block_bytes_read = 0;
    unsigned char block[BLOCK_SIZE];

    do
    {
         block_bytes_read = fread (block,sizeof(char),BLOCK,file);
         buffer = realloc(buffer, block_bytes_read*sizeof(char));
         memcpy((buffer + bytes_read), block, block_bytes_read*sizeof(char));
         bytes_read += block_bytes_read;
    } while (block_bytes_read != 0);

   return bytes_read;

}
于 2013-04-25T08:18:40.230 回答
0

制作buffer一个静态变量,这样它就不会驻留在堆栈上。

此外,fread请在循环内使用,因为不能保证一次读取所有文件。

于 2013-04-25T08:19:13.503 回答
0

这段代码我最大的问题是在这一行:

fread (buffer,sizeof(int),4000000,fp);

实际上,这一行引入了一系列重要的问题。首先,不能保证您正在读取的文件已成功打开。正如其他人所指出的那样,您需要进行比较fp才能NULL做出保证。其次,我似乎经常强调这种方式:你真的应该检查 return value。这适用于所有标准 C 函数,而不仅仅是fopenfread

fread的返回值告诉您实际读取了多少项目。假设您请求 400 万个ints,而该文件仅包含两个。返回值会告诉你只int读取了两个 s。


现在,进入大事!让我们首先考虑sizeof(int)在不同的实现上有所不同。您的系统可能会读取 4 个字节,而另一个可能会读取 2 个字节,而另一个可能会读取 8 个字节。这只是整数表示可能不同的基本但基本方式。

让我们考虑一种更微妙但同样具有破坏性的整数表示可能不同的方式:假设您int的 s 是四个字节,最左边的位是最低有效位。另一台机器可能使用最左边的位作为最低有效位。同样,考虑字节顺序,即字节顺序。

假设您int的 s 是 32 位,它们代表 和 之间的值-(1 << 31)(1 << 31)这意味着没有填充位。另一个系统可能使用具有 16 位填充的 32 位整数,这意味着它可能只表示 和 之间的-(1 << 16)(1 << 16)。假设这些填充位是奇偶校验位,以确保 RAM 正常运行(例如 Intel Xeon 服务器)。现在,您的服务器会告诉您 RAM 有故障,而实际上并非如此。

您的代码应明确地将文件用于存储整数的整数表示转换为计算机本机使用的任何表示。将整数写入文件时,您需要确保将实现表示明确转换为该表示。同样,当从文件中读回整数时,您的代码应该将该表示显式转换为您的实现表示。

例如,让我们假设您的int值不会超出-3276732767(16 位有符号整数,一个的补码)。使用两个字节表示它是可移植的,但您需要明确定义该整数的符号和表示。写入时,您可以提取符号和绝对值,然后写入sign * 128 + absolute_value / 256文件absolute_value % 256。阅读时,您将提取符号位,乘以并添加以重建您的值。


让我们考虑一下您的文件应该是 4MB,但您正在读取sizeof (int) * 4000000值。4MB 是0x400000,不是sizeof (int) * 4000000。我想您真正想要的是以下内容:

unsigned char *foo = malloc(0x400000); /* 4MB */

/* XXX: Handle malloc errors here */
assert(foo != NULL);

FILE *fp = fopen("file.bin", "rb");

/* XXX: Handle fopen errors here */
assert(fp != NULL);

size_t num_bytes_read = fread(foo, 1, 0x400000, fp);

/* XXX: Transform the bytes into integers */

free(foo);

我的问题是它依赖一个 4MB 的缓冲区来读取字节并将其转换为整数。这个任务根本不需要缓冲区!

FILE *fp = fopen("file.bin", "rb");

/* XXX: Handle fopen errors here */
assert(fp != NULL);

for (;;) {
    int x = fgetc(fp);

    /* XXX: Handle fgetc errors here */
    assert(x >= 0);

    int y = fgetc(fp);

    /* XXX: Handle fgetc errors here */
    assert(y >= 0);

    /* XXX: Transform the characters in x and y into the int values */
};

free(foo);

问题中未指定您是否需要将这些转换后的值存储在某处。如果您不需要,那么我的下一个问题是数组的使用,当您可能只是读取单个项目,处理它然后移动到下一个项目时。

于 2013-04-25T09:14:06.100 回答