有没有一种可移植的方法来管理存储在Linux中的映射文件中的结构数据,而不是逐字节地读取它?

时间:2016-12-26 12:19:17

标签: c linux mmap

我想说我要存储一个C数组(固定长度N)的结构:

typedef struct {
  type0 field0;
  type1 field1;
} foo_struct;

foo_struct array[N];

在一个文件中,以便程序可以从文件中读取数组,对其进行操作并将其写回。

程序可以使用系统调用write来编写typen的每个实例。然后当我们调用程序读取时,如果我们假设sizeof(typen)返回与之前相同的内容,我们可以在内存中分配数组,并使用read来填充字段。我认为由于可移植性问题,没有办法可以立即可靠地填充整个结构,如果我错了,请纠正我。

但这对我来说太慢了。即使我立刻将所有内容读入大缓冲区,我也必须复制到字段中。发生的事情是我的数据大小是" yuuge",但操作是零星的。读取和复制将比实际数据访问花费更多时间。

所以我更喜欢使用mmap而我假设mmap按需工作 - 如果我错了,请再次纠正我。

现在,这可能会更快,但我在访问内存中的数据时会遇到一些麻烦。

mmap指定一个返回值本身是一个坏主意,该函数会为您返回缓冲区,但不保证对齐,即使它在sizeof(foo_struct)的倍数上对齐,这仍然无法保证我可以访问带有指向结构和->运算符的指针的字段。

所以我认为,我必须忘记识别结构,只需将我的数组视为一系列大小S0 = sizeof(field0) S1 = sizeof(field1) S = S0 + S1,并按以下方式计算:通过使用指针算法来获取数据的位置:

buffer + M * S
buffer + M * S + S0

然后,即使该指针未对齐,所以如果我想读取或写入fieldn,我必须将数据拆分为字节并逐字节地执行,这很慢。尽管这些访问并不多,但是,整个过程有很多次迭代,所以我仍然要尽可能快地完成它。

有没有办法使用mmap(或其他一些方式让我不必阅读整个yuuge文件),但是,不必逐个字段和字节访问数据逐字节?

如果我写的一些内容违反Linux或普通体面,请分享,因为我不完全确定它没有。

1 个答案:

答案 0 :(得分:1)

仅出于演示目的,标准从二进制文件中读取struct-array

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

struct omg{
        int num;
        char buff[122];
        double values[23];
        };

#define NNN (3*1024*1024)
#define FILENAME "omg.dat"
#define COUNTOF(a) (sizeof a/sizeof a[0])

struct omg array[NNN];

int main(void)
{
int fd;
int ret, ii, jj;

fprintf(stderr, "Sizeof array[0] is %zu\n", sizeof array[0] );
        /* initialise the array to nonsence */
for (ii=0; ii < COUNTOF(array); ii++) {
        array[ii].num=ii;
        sprintf(array[ii].buff, "Hello world %d", ii);
        for (jj=0; jj < COUNTOF(array[0].values); jj++) {
                array[ii].values[jj] = ii / (jj+1) ;
                }
        }

fd = open(FILENAME, O_RDWR|O_CREAT, 0660);
if (fd < 0) return 1;

ret = read(fd, array, sizeof array);
fprintf(stderr, "Read %d/ %zu\n", ret, sizeof array);

        /* modify the nonsence */
for (ii=0; ii < COUNTOF(array); ii++) {
        array[ii].num += 1;
        sprintf(array[ii].buff, "Hello world %d", array[ii].num);
        for (jj=0; jj < COUNTOF(array[0].values); jj++) {
                array[ii].values[jj] = array[ii].num / (jj+1) ;
                }
        }

ret = lseek(fd, 0, SEEK_SET);
fprintf(stderr, "Seek = %d\n", ret);


ret = write(fd, array, sizeof array);
fprintf(stderr, "Wrote %d/ %zu\n", ret, sizeof array);

close(fd);
return 0;
}

结果:

plasser@pisbak$ vi readstruct.c
plasser@pisbak$ cc -Wall -O2 readstruct.c
plasser@pisbak$ time ./a.out
Sizeof array[0] is 312
Read 981467136/ 981467136
Wrote 981467136/ 981467136

real    0m3.972s
user    0m1.689s
sys     0m0.782s

现在,我不会在4秒中打电话给读书加900MB。 大多数用户CPU可能被sprintf()调用消耗。