2009-08-14 4 views
0

Я пытаюсь объединить два больших файла (например, команда cat UNIX: cat file1 file2> final) в C++.Объединить большие файлы

Я не знаю, как это сделать, потому что каждый метод, который я стараюсь это очень медленно (например, скопировать второй файл в первую одну строку за строкой)

¿Что такое лучший метод для дел что?

Извините за столь краткий, мой английский не слишком хорошо

+0

Просьба представить более подробную информацию о вашей реализации (STDIO, iostream и т.д.) и требований (бинарных, текст и т.д.) –

ответ

6

Использование двоичного режима в стандартных потоков, чтобы сделать эту работу, не иметь дело с ним, как отформатированных данных.


Это демо, если вы хотите передать данные в блоках:

#include <fstream> 
#include <vector> 

std::size_t fileSize(std::ifstream& file) 
{ 
    std::size_t size; 

    file.seekg(0, std::ios::end); 
    size = file.tellg(); 
    file.seekg(0, std::ios::beg); 

    return size; 
} 

int main() 
{ 
    // 1MB! choose a conveinent buffer size. 
    const std::size_t blockSize = 1024 * 1024; 

    std::vector<char> data(blockSize); 
    std::ifstream first("first.txt", std::ios::binary), 
       second("second.txt", std::ios::binary); 
    std::ofstream result("result.txt", std::ios::binary); 
    std::size_t firstSize = fileSize(first); 
    std::size_t secondSize = fileSize(second); 

    for(std::size_t block = 0; block < firstSize/blockSize; block++) 
    { 
     first.read(&data[0], blockSize); 
     result.write(&data[0], blockSize); 
    } 

    std::size_t firstFilerestOfData = firstSize%blockSize; 

    if(firstFilerestOfData != 0) 
    { 
     first.read(&data[0], firstFilerestOfData); 
     result.write(&data[0], firstFilerestOfData); 
    } 

    for(std::size_t block = 0; block < secondSize/blockSize; block++) 
    { 
     second.read(&data[0], blockSize); 
     result.write(&data[0], blockSize); 
    } 

    std::size_t secondFilerestOfData = secondSize%blockSize; 

    if(secondFilerestOfData != 0) 
    { 
     second.read(&data[0], secondFilerestOfData); 
     result.write(&data[0], secondFilerestOfData); 
    } 

    first.close(); 
    second.close(); 
    result.close(); 

    return 0; 
} 
+0

и использовать большой размер блока (несколько кб, по крайней мере) – bdonlan

2

Используя обычный старый C++:

#include <fstream> 

std::ifstream file1("x", ios_base::in | ios_base::binary); 
std::ofstream file2("y", ios_base::app | ios_base::binary); 
file2 << file1.rdbuf(); 

подпиточного заголовки утверждают, что copy() оптимизирован в некоторых случаях , хотя я не уверен, имеет ли это значение следующее:

#include <boost/iostreams/copy.hpp> 
// The following four overloads of copy_impl() optimize 
// copying in the case that one or both of the two devices 
// models Direct (see 
// http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4) 

boost::iostreams::copy(file1, file2); 

обновление:

Функция подталкивания копия совместима с широким разнообразием типов, так что это может быть объединено с предложением Павла Минаева использования std::filebuf как так:

std::filebuf file1, file2; 

file1.open("x", ios_base::in | ios_base::binary); 
file2.open("y", ios_base::app | ios_base::binary); 

file1.setbuf(NULL, 64 * 1024); 
file2.setbuf(NULL, 64 * 1024); 

boost::iostreams::copy(file1, file2); 

Конечно фактический оптимальный размер буфера зависит от многих переменных, 64k - просто дикая догадка.

+0

Заметьте, что << and >> операторы в основном используются для форматированного I/o и поэтому не так эффективны, как использование чтения и записи с двоичными данными. –

+0

Обычно да, но 'rdbuf()' возвращает 'streambuf *', и я уверен, что соответствующий 'operator <<' overload делает прямую копию без форматирования. –

0

В качестве альтернативы, которая может быть или не быть быстрее в зависимости от размера и объема вашего файла на машине. Если память плотная, вы можете уменьшить размер буфера и зациклиться на f2.read, захватывая данные в кусках и записывая в f1.

 
#include <fstream> 
#include <iostream> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
     ofstream f1("test.txt", ios_base::app | ios_base::binary); 
     ifstream f2("test2.txt"); 

     f2.seekg(0,ifstream::end); 
     unsigned long size = f2.tellg(); 
     f2.seekg(0); 

     char *contents = new char[size]; 
     f2.read(contents, size); 
     f1.write(contents, size); 

     delete[] contents; 
     f1.close(); 
     f2.close(); 

     return 1; 
} 

6

Если вы используете std::fstream, то этого не делать. Он предназначен в первую очередь для форматированного ввода/вывода, а для него операции с char-level - slower than you'd expect. Вместо этого используйте std::filebuf напрямую. Это в дополнение к предложениям в других ответах, в частности, с использованием большего размера буфера.

+1

+1 для std :: filebuf – AraK

Смежные вопросы