2011-01-31 10 views
2

私は各行に整数が書かれた2つのテキストファイルをmmapingしています。 私はドライブからそれらを読んで、私は彼らにソートされたマージをしたいと思いました。 2つの入力ファイル "1piece0"と "1piece1"にはソートされた整数のリストがあります。 出力ファイルのサイズは、2つのファイルを結合したものの、それほど多くの整数ではありません。 問題:2つの入力ファイルには25430000行があり、出力ファイルには50860000行ありますが、17259463行しかありません。 これは私の現在のコードです。std :: mergeは2 mmaped配列を使用していますか?

#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; 
} 

私が間違っていることを教えてもらえますか?

更新:行は、整数と改行文字を意味します。

+1

は私たちに間違って何が起こっているかについての詳細を教えてください。 –

+0

@Jens - まあ、ファイルは整数と改行文字の形になっています。 そこで私はそれらをマージするようにソートしたかったのです。私はそれらをmmapできないと思う。 正確な問題は、出力ファイルに十分な行がないように見えることです。 –

+0

map2とmap3の隣にあるif条件は、mapではなくmap2とmap3をチェックしてはいけませんか? – yasouser

答えて

2

テキスト行をバイナリブロブとして扱い、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(); 
} 
+0

ストリームを使用したくない主な理由は、ストリームが遅すぎるということです。 私はできるだけ早くプログラムを望んでいました。 私はメインメモリが100MBしかないので、それらをmmapしたいと思っていましたが、メモリ上のチャンクにそれらを格納してマージを実行するコードを書く必要があると思います。 CファイルI/Oが高速ですそれ?私はそれを使うべきではありませんか? –

+0

@Skkard:どうしてテストしないの? scanf-familyの使用も問題ありません。要点は、テキストデータがある場合、それを非テキスト(「バイナリ」)データとして扱うことができないことです。 –

+1

速いですが、期待したほどではありません。 問題をクリアしていただきありがとうございます:) –

2

「ライン」とはどういう意味ですか?

メモリマップすると、メモリのようにデータが扱われ、ここではintの配列のように読み取られます。したがって、入力はネイティブのバイナリ形式(つまり、バイトが同じ方法、同じサイズおよび同じエンディアンで格納されている)でなければならず、25430000は各コレクションから読み込んでいるintの数です。

入力はどのように格納されますか?

ここには多くの「魔法の数字」があります。

+0

テキストファイルです。バイナリファイルに変換する必要がありますか? どうすればいいですか? –

+0

このようにする必要がある場合は、ストリームを使用してテキストを読むことができます。最も簡単な方法は、オープンファイルハンドル(ifstream)に対してistream_iterator を入力イテレータタイプとして使用することです。 – CashCow

関連する問題