【问题标题】:std::merge using 2 mmaped arrays?std::merge 使用 2 个映射数组?
【发布时间】:2011-01-31 09:46:26
【问题描述】:

我正在映射两个文本文件,每行写一个整数。 我从驱动器中读取它们,我想对它们进行排序合并。 两个输入文件“1piece0”和“1piece1”有一个排序整数列表。 输出文件确实具有两个文件组合的大小,但没有那么多整数。 问题:两个输入文件有 25430000 行,而输出文件应该有 50860000 行但它只有 17259463 行。 这是我当前的代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <algorithm>

#define FILESIZE 25430000 * sizeof(int)
#define FILE0 279288034
#define FILE1 279287226
int main()
{
    int i;
    int fd;
    int fd2;
    int fd3;
    int result;
    int *map;
    int *map2;
    int *map3;

    fd3 = open( "file.out", O_RDWR | O_CREAT | O_TRUNC, (mode_t)0755);
    if ( fd3 == -1 ) {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }
    result = lseek(fd3, FILE0 + FILE1 - 1, SEEK_SET );
    if(result == -1) {
        close(fd);
        perror("Error calling lseek\n");
        exit(EXIT_FAILURE);
    }

    result = write(fd3,"",1);
    if( result != 1 ) {
        close(fd3);
        perror("error writing last byte");
        exit(EXIT_FAILURE);
    }
    map3 =(int *) mmap(0, FILE0 + FILE1, PROT_READ | PROT_WRITE, MAP_SHARED, fd3, 0);
    if( map == MAP_FAILED ) {
        close(fd);
        perror("Error mmapinG fd3");
        exit(EXIT_FAILURE);
    }


    fd = open( "1piece0", O_RDONLY );
    if( fd == -1 ) {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }

    map = (int *)mmap(0, FILE0, PROT_READ, MAP_SHARED, fd, 0 );
    if( map == MAP_FAILED ) {
        close(fd);
        perror("error mapping file");
        exit(EXIT_FAILURE);
    }

    fd2 = open( "1piece1", O_RDONLY );
    if( fd2 == -1 ) {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }

    map2 = (int *)mmap(0, FILE1, PROT_READ, MAP_SHARED, fd2, 0 );
    if( map == MAP_FAILED ) {
        close(fd2);
        perror("error mapping file");
        exit(EXIT_FAILURE);
    }

//  while(1);
    std::merge( map, map + 25430000, map2, map2 + 25430000, map3 );

    if(munmap(map, FILE0 ) == -1 ) {
        perror("error unmapping map");
    }
    close(fd);

    if(munmap(map3, FILE0 + FILE1 ) == -1 ) {
        perror("error unmapping map3");
    }
    close(fd3);

    if(munmap(map2, FILE1 ) == -1 ) {
        perror("error unmapping map2");
    }
    close(fd2);

    return 0;
}

你能告诉我我做错了什么吗?

更新:我所说的行是一个整数,然后是一个换行符。

【问题讨论】:

  • 告诉我们更多关于出了什么问题。
  • @Jens - 文件是整数形式,然后是换行符。所以我想对它们进行排序合并。我想我无法映射它们。确切的问题是输出文件中似乎没有足够的行数。
  • map2 和 map3 旁边的 if 条件不应该检查 map2 和 map3,而不是 map?

标签: c++ c unix stl mmap


【解决方案1】:

您不能将文本行视为二进制 blob 以作为 int 指针进行操作。

您可以将文本文件视为文本为extracted and used

void merge_ints(std::istream &a_in, std::istream &b_in, std::ostream &out) {
  int a, b;
  std::istream *remaining = 0;
  if (!(a_in >> a)) {
    remaining = &b_in;
  }
  else if (!(b_in >> b)) {
    out << a << '\n';
    remaining = &a_in;
  }
  else while (a_in && b_in) {
    if (a < b) {
      out << a << '\n';
      if (!(a_in >> a)) {
        out << b << '\n';
        remaining = &b_in;
      }
    }
    else {
      out << b << '\n';
      if (!(b_in >> b)) {
        out << a << '\n';
        remaining = &a_in;
      }
    }
  }
  for (int x; *remaining >> x;) {
    out << x << '\n';
  }
}

Taking advantage of std::merge:

void merge_ints(std::istream &a, std::istream &b, std::ostream &out) {
  typedef std::istream_iterator<int> In;
  std::merge(In(a), In(), In(b), In(), std::ostream_iterator<int>(out, "\n"));
}

int main() {
  stringstream a ("1\n3\n5\n"), b ("2\n4\n6\n7\n"), out;
  merge_ints(a, b, out);
  cout << out.str();
}

【讨论】:

  • 我不想使用流的主要原因是它们太慢了。我希望程序尽可能快。我只有 100mb 的主内存,所以我想对它们进行映射,但我想我必须编写代码将它们存储在内存中的块中并执行合并。C 文件 I/O 更快不是吗?我不应该使用它吗?
  • @Skkard:你为什么不测试一下?使用 scanf-family 也很好。要点是,如果您有文本数据,则不能将其视为非文本(“二进制”)数据。
  • 它更快,但没有我希望的那么多。感谢您清理一切:)。
【解决方案2】:

“线”是什么意思?

当您进行内存映射时,它会将数据视为内存,在这里您将其视为整数数组。因此,输入必须是原生二进制格式(即字节以相同的方式、相同的大小和相同的字节顺序存储),并且 25430000 是您从每个集合中读取的整数数。

你的输入是这样存储的吗?

这里有很多“神奇的数字”。

【讨论】:

  • 这是一个文本文件。我应该将其转换为二进制文件吗?我该怎么做?
  • 如果你这样做,你需要这样做,但你可以使用流来阅读文本。最简单的方法是在打开的文件句柄 (ifstream) 上使用 istream_iterator 作为输入迭代器类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2021-10-27
相关资源
最近更新 更多