创建仅包含文件内存位置的动态数组

时间:2014-08-04 15:28:54

标签: c arrays

我有一些文件* fp,它在数组中以文件标题“header”之后的4个字节的偏移量布局。

如何使用类型转换仅使用内存中的位置从该数组中读取单个结构?

会是这样的吗?

struct_name *arr = (struct_name *) &header + 4; 

struct_name x = arr[1];

我正在做类似但却出现分段错误。有什么需要在这里进行malloc-ed?

2 个答案:

答案 0 :(得分:0)

该文件需要加载到内存中,为了能够将此内存转换为结构,您有两个常用选项

  • 将所有内容读入缓冲区(示例代码中的C和C ++版本)。
  • 使用boost::iostreams::mapped_file映射文件(示例代码中的C ++版本)。在C中,您可以使用特定于平台的功能(Linux中为mmap,Windows中为CreateFileMappingMapViewOfFile。)

注意:要编译的struct的所有元素类型的大小必须在编译时知道(没有std :: string,或者在运行时分配内存的任何其他类型)。您需要在缓冲区中加载至少数组的内存以进行强制转换和迭代。

示例代码(使用C ++ 11在GCC 4.9.0中测试):

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <boost/iostreams/device/mapped_file.hpp>

struct data {
    int a, b;
};

int main() {
    // C version
    FILE* fp = fopen("E:\\save.txt", "rb");
    if (!fp)
        return -1;

    fseek(fp, 0L, SEEK_END);
    int size0 = ftell(fp);
    fseek(fp, 0L, SEEK_SET);

    char* cbuffer = (char*)malloc(size0);
    fread(cbuffer, 1, size0, fp);
    fclose(fp);

    for (unsigned int idx = 0; idx < size0; idx++)
        std::cout << (long)cbuffer[idx] << ",";
    std::cout << std::endl;

    data* data0 = (data*)&cbuffer[0];
    for (int i = 0; i < 2; i++) {
        std::cout << std::hex << data0[i].a << std::endl;
    }

    delete cbuffer;
    // End C version

    // C++ Version
    std::ifstream ifs("E:\\save.txt", std::ios_base::binary | std::ios_base::in);

    if (!ifs.good())
        return -1;

    ifs.seekg(0, std::ios_base::end);
    long long size = ifs.tellg();

    std::vector<unsigned char> buffer(size);
    ifs.seekg(0, std::ios_base::beg);
    ifs.read((char*)&buffer[0], buffer.size());
    ifs.close();

    for (auto d : buffer)
        std::cout << (long)d << ",";
    std::cout << std::endl;

    data* data1 = (data*)&buffer[0];
    for (int i = 0; i < 2; i++) {
        std::cout << std::hex << data1[i].a << std::endl;
    }
    // End C++ Version

    // C++ Mapped File
    boost::iostreams::mapped_file mmfile("E:\\save.txt");

    for (unsigned int idx = 0; idx < mmfile.size(); idx++)
        std::cout << (long)mmfile.data()[idx] << ",";
    std::cout << std::endl;

    data* data2 = (data*)mmfile.data();
    for (int i = 0; i < 2; i++) {
        std::cout << std::hex << data2[i].b << std::endl;
    }
    mmfile.close();
    // End C++ Mapped File

    return 0;
}

答案 1 :(得分:0)

你问题中的(struct_name*)&header意味着一种根本的误解。

除非这个变量存储文件的整个数据(而不仅仅是标题),否则使用它的地址可能是一个非常糟糕的主意,因为其余数据不会出现在&#34;之后#34; ;

因此,下面的答案假设您已将整个文件读入char* data所指向的内存中。


理论上,你可以这样做:

element_struct  val;
element_struct* ptr = (element_struct*)(data+sizeof(header_struct)+4);

// Read the n-th element (starting from 0)
val = ptr[n];

但是,由于未对齐的内存访问操作,这可能是不安全的。


因此,这是一种更安全的方法:

element_struct val;
char* ptr = data+sizeof(header_struct)+4;

// Read the n-th element (starting from 0)
memcpy(&val,ptr+n*sizeof(element_struct),sizeof(element_struct));

除了上述内容之外,您还需要确保编译器添加到结构中的填充,准确反映了数据在文件中的布局方式。