10

我有两个 std::ofstream 文本文件,每个文件都有一百多个,我想将它们连接起来。使用 fstreams 存储数据以创建单个文件通常会出现内存不足错误,因为大小太大。

有什么方法可以比 O(n) 更快地合并它们?

文件 1 (160MB):

0 1 3 5
7 9 11 13
...
...
9187653 9187655 9187657 9187659 

文件 2 (120MB):

a b c d e f g h i j
a b c d e f g h j i
a b c d e f g i h j
a b c d e f g i j h
...
...
j i h g f e d c b a

合并(380MB):

0 1 3 5
7 9 11 13
...
...
9187653 9187655 9187657 9187659 
a b c d e f g h i j
a b c d e f g h j i
a b c d e f g i h j
a b c d e f g i j h
...
...
j i h g f e d c b a

文件生成:

std::ofstream a_file ( "file1.txt" );
std::ofstream b_file ( "file2.txt" );

    while(//whatever){
          a_file << num << endl;
    }

    while(//whatever){
          b_file << character << endl;
    }

    // merge them here, doesn't matter if output is one of them or a new file
    a_file.close();
    b_file.close();
4

4 回答 4

20

假设您不想进行任何处理,只想连接两个文件以制作第三个文件,您可以通过流式传输文件的缓冲区来非常简单地做到这一点:

std::ifstream if_a("a.txt", std::ios_base::binary);
std::ifstream if_b("b.txt", std::ios_base::binary);
std::ofstream of_c("c.txt", std::ios_base::binary);

of_c << if_a.rdbuf() << if_b.rdbuf();

我过去曾尝试过使用高达 100Mb 的文件进行此类操作,但没有任何问题。您有效地让 C++ 和库处理所需的任何缓冲。这也意味着如果您的文件变得非常大,您无需担心文件位置。

另一种方法是,如果您只想复制b.txt到 的末尾a.txt,在这种情况下,您需要a.txt使用附加标志打开,然后查找到末尾:

std::ofstream of_a("a.txt", std::ios_base::binary | std::ios_base::app);
std::ifstream if_b("b.txt", std::ios_base::binary);

of_a.seekp(0, std::ios_base::end);
of_a << if_b.rdbuf();

这些方法的工作原理是将std::streambuf输入流operator<<的 如该链接中所述,在没有错误的情况下,将无格式插入到输出流中,直到文件末尾。streambufstreambuf

于 2013-10-24T13:29:49.947 回答
5

有什么方法可以比 O(n) 更快地合并它们?

这意味着您将处理数据而无需通过它一次。如果不至少阅读一次,您就无法将其解释为合并(简短回答:否)。

对于读取数据,您应该考虑无缓冲读取(查看 std::fstream::read)。

于 2013-10-24T11:25:31.777 回答
2

这实际上取决于您是否希望为此使用“纯” C++,个人以牺牲可移植性为代价,我很想写:

#include <cstdlib>
#include <sstream>

int main(int argc, char* argv[]) {
    std::ostringstream command;

    command << "cat "; // Linux Only, command for Windows is slightly different

    for (int i = 2; i < argc; ++i) { command << argv[i] << " "; }

    command << "> ";

    command << argv[1];

    return system(command.str().c_str());
}

它是好的 C++ 代码吗?不,不是真的(不可移植且不会转义命令参数)。

但它会让你领先于你现在所处的位置。

至于“真正的” C++ 解决方案,流可以管理的所有丑陋......

#include <fstream>
#include <string>

static size_t const BufferSize = 8192; // 8 KB

void appendFile(std::string const& outFile, std::string const& inFile) {
    std::ofstream out(outFile, std::ios_base::app |
                               std::ios_base::binary |
                               std::ios_base::out);

    std::ifstream in(inFile, std::ios_base::binary |
                             std::ios_base::in);

    std::vector<char> buffer(BufferSize);
    while (in.read(&buffer[0], buffer.size())) {
        out.write(&buffer[0], buffer.size());
    }

    // Fails when "read" encounters EOF,
    // but potentially still writes *some* bytes to buffer!
    out.write(&buffer[0], in.gcount());
}
于 2013-10-24T11:59:47.523 回答
2

在 Windows 上:-

system ("copy File1+File2 OutputFile");

在 Linux 上:-

system ("cat File1 File2 > OutputFile");

但答案很简单——不要将整个文件读入内存!以小块读取输入文件:-

void Cat (input_file, output_file)
{
  while ((bytes_read = read_data (input_file, buffer, buffer_size)) != 0)
  { 
    write_data (output_file, buffer, bytes_read);
  }
}

int main ()
{
   output_file = open output file

   input_file = open input file1
   Cat (input_file, output_file)
   close input_file

   input_file = open input file2
   Cat (input_file, output_file)
   close input_file
}
于 2013-10-24T11:58:12.953 回答