gpt4 book ai didi

c++ - 将内存映射数据 block 读入结构

转载 作者:可可西里 更新时间:2023-11-01 10:59:11 24 4
gpt4 key购买 nike

我今天一直在 VC++ 2008 上研究内存映射,但我仍然没有完全理解如何使用它或者它是否适合我的目的。我的目标是快速读取一个非常大的二进制文件。

我有一个结构:

typedef struct _data
{
int number;
char character[512];
float *entries;
}Data;

多次写入文件。 “条目”变量是一个浮点小数数组。写入此文件后(10000 个数据结构,每个“条目”数组为 90000 个 float ),我尝试使用以下函数内存映射此文件,以便我可以更快地读取数据。这是我到目前为止所拥有的:

void readDataMmap(char *fname,      //name of file containing my data
int arraySize, //number of values in struct Data
int entrySize) //number of values in each "entries" array
{
//Read and mem map the file
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hMapFile;
char* pBuf;

int fd = open(fname, O_RDONLY);
if(fd == -1){
printf("Error: read failed");
exit(-1);
}

hFile = CreateFile((TCHAR*)fname,
GENERIC_READ, // open for reading
0, // do not share
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no template

if (hFile == INVALID_HANDLE_VALUE)
{
printf("First CreateFile failed"));
return (1);
}

hMapFile = CreateFileMapping(hFile,
NULL, // default security
PAGE_READWRITE,
0, // max. object size
0, // buffer size
NULL); // name of mapping object

if(hMapFile == ERROR_FILE_INVALID){
printf("File Mapping failed");
return(2);
}

pBuf = (char*) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_READ, // read/write permission
0,
0,
0); //Was NULL, 0 should represent full file bytesToMap size
if (pBuf == NULL)
{
printf("Could not map view of file\n");
CloseHandle(hMapFile);

return 1;
}

//Allocate data structure
Data *inData = new Data[arraySize];
for(int i = 0; i<arraySize; i++)inData[i].entries = new float[entrySize];

int pos = 0;
for(int i = 0; i < arraySize; i++)
{
//This is where I'm not sure what to do with the memory block
}
}

在函数的最后,内存被映射后,我返回了一个指向内存块“pBuf”开头的指针,我不知道该怎么做才能读回这个内存块进入我的数据结构。所以最终我想将这个内存块传输回我的 10000 数据结构条目数组。当然,我可能做错了......

最佳答案

处理内存映射文件实际上与处理任何其他类型的内存指针没有什么不同。内存映射文件只是一个数据 block ,您可以使用相同的名称从任何进程读取和写入它。

我假设您想将文件加载到内存映射中,然后在那里随意读取和更新它,并以某个固定或已知的时间间隔将其转储到文件中,对吗?如果是这种情况,那么只需从文件中读取并将数据复制到内存映射指针即可。稍后您可以从 map 中读取数据并将其转换为内存对齐结构并随意使用您的结构。

如果我是你,我可能会创建一些辅助方法,例如

数据读取数据(void *ptr)

void WriteData(data *ptrToData, void *ptr)

*ptr 是内存映射地址,*ptrToData 是指向要写入内存的数据结构的指针。真的在这一点上它的内存是否映射并不重要,如果你想从加载到本地内存的文件中读取你也可以这样做。

您可以使用 memcpy 将数据从源复制到目标,以与任何其他 block 数据相同的方式对其进行读/写,并且可以使用指针算法来推进数据中的位置。不要担心“内存映射”,它只是一个指向内存的指针,您可以这样对待它。

此外,由于您将要处理直接内存指针,因此您不需要将每个元素一个一个地写入映射文件,您可以将它们全部写入一批,如

memcpy(mapPointer, data->entries, sizeof(float)*number)

data->entries 中的 float*entries 大小复制到映射指针起始地址。显然你可以随心所欲地复制它,无论你想要什么,这只是一个例子。参见 http://www.devx.com/tips/Tip/13291 .

读回数据的方式与您类似,但您希望将内存地址显式复制到已知位置,因此想象一下将您的结构展平。而不是

data:
int
char * -> points to some address
float * -> points to some address

在你的指针指向其他地方的其他内存的地方,像这样复制内存

data:
int
char * -> copy of original ptr
float * -> copy of original ptr
512 values of char array
number of values of float array

所以这样你就可以将内存映射中的数据“重新序列化”到你的本地。请记住,数组只是指向内存的指针。内存在对象中不必是连续的,因为它可以在其他时间分配。您需要确保将指针指向的实际数据复制到您的内存映射中。这样做的一种常见方法是将对象直接写入内存映射,然后在对象后面加上所有展平的数组。读回它首先读取对象,然后将指针增加 sizeof(object) 并读取下一个数组,然后再次将指针增加 arraysize 等。

这是一个例子:

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

typedef struct data{
int size;
char items[512];
float * dataPoints;
};

void writeToBuffer(data *input, char *buffer){
int sizeOfData = sizeof(data);
int dataPointsSize = sizeof(float) * input->size;

printf("size of data %d\n", sizeOfData);

memcpy(buffer, input, sizeOfData);

printf("pointer to dataPoints of original %x\n", input->dataPoints);

memcpy(buffer + sizeOfData, input->dataPoints, dataPointsSize);
}

void readFromBuffer(data *target, char * buffer){
memcpy(target, buffer, sizeof(data));

printf("pointer to datapoints of copy %x, same as original\n", target->dataPoints);


// give ourselves a new array
target->dataPoints = (float *)malloc(target->size * sizeof(float));

// do a deep copy, since we just copied the same pointer from
// the previous data into our local

memcpy(target->dataPoints, buffer + sizeof(data), target->size * sizeof(float));

printf("pointer to datapoints of copy %x, now it's own copy\n", target->dataPoints);
}

int main(int argc, char* argv[])
{
data test;

for(unsigned int i=0;i<512;i++){
test.items[i] = i;
}

test.size = 10;

// create an array and populate the data
test.dataPoints = new float[test.size];

for(unsigned int i=0;i<test.size;i++){
test.dataPoints[i] = (float)i * (1000.0);
}

// print it out for demosntration
for(unsigned int i=0;i<test.size;i++){
printf("data point value %d: %f\n", i, test.dataPoints[i]);
}

// create a memory buffer. this is no different than the shared memory
char * memBuffer = (char*)malloc(sizeof(data) + 512 + sizeof(float) * test.size + 200);

// create a target we'll load values into
data test2;

// write the original out to the memory buffer
writeToBuffer(&test, memBuffer);

// read from the memory buffer into the target
readFromBuffer(&test2, memBuffer);

// print for demonstration
printf("copy number %d\n", test2.size);
for(int i=0;i<test2.size;i++){
printf("\tcopy value %d: %f\n", i, test2.dataPoints[i]);
}

// memory cleanup

delete memBuffer;
delete [] test.dataPoints;

return 0;
}

在将数据从结构体写入内存时,您可能还想阅读有关数据对齐的内容。检查working with packing structures , C++ struct alignment question , 和 data structure alignment .

如果在读取时不知道数据的大小,则应将数据的大小写入内存映射的开头已知位置,以备后用。

无论如何,要解决我认为在这里使用它是否正确的事实。来自 wikipedia

The primary benefit of memory mapping a file is increasing I/O performance, especially when used on large files. ... The memory mapping process is handled by the virtual memory manager, which is the same subsystem responsible for dealing with the page file. Memory mapped files are loaded into memory one entire page at a time. The page size is selected by the operating system for maximum performance. Since page file management is one of the most critical elements of a virtual memory system, loading page sized sections of a file into physical memory is typically a very highly optimized system function.

您要将整个文件加载到虚拟内存中,然后操作系统可以根据需要为您将文件分页进出内存,从而创建“延迟加载”机制。

总而言之,内存映射是共享的,因此如果它跨进程边界,您需要将它们与命名的互斥锁同步,这样您就不会覆盖进程之间的数据。

关于c++ - 将内存映射数据 block 读入结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12790820/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com