Программа для конвертации файлов однотипных записей
От: mezhaka  
Дата: 10.11.10 19:19
Оценка:
Был бы рад, если бы кто-нибудь покритиковал эту маленькую программку.
Нужно было сконвертировать большой файл состоящий из double в файл состоящий из float. По идее эту програмку можно использовать для конвертации любых простых POD струкур. Первая версия этой программы открывала поток, читала по одному значению и сразу его писала в другой поток. Конвертация трёхгигового файла занимала:

$ time double2float tmp.double tmp.float

real    1m24.239s
user    1m9.987s
sys     0m8.628s

Для сравнения, копирование файла занимает столько:

$ time cp input.vel.double tmp.double

real 0m13.322s
user 0m0.521s
sys 0m10.723s[/code]

Эта версия с буффером отрабатывает заметно быстрее:
[code]
$ time double2float tmp.double tmp.float

real    0m9.680s
user    0m1.511s
sys     0m7.625s


Вот код:
#include <algorithm>
#include <cassert>
#include <fstream>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

template<typename UnaryFunction>
void buffered_binary_stream_transform(std::ifstream& input, std::ofstream& output, UnaryFunction op, size_t buffer_size_bytes)
{
    typedef typename UnaryFunction::argument_type argument_type;
    typedef typename UnaryFunction::result_type result_type;

    const size_t argument_type_size = sizeof(argument_type);
    assert(buffer_size_bytes >= argument_type_size);

    const size_t result_type_size = sizeof(result_type);
    const typename std::vector<argument_type>::size_type buffer_size_elements = buffer_size_bytes / argument_type_size; //might truncate actual buffer_size_bytes 
    const int bytes_to_read = argument_type_size * buffer_size_elements;
    std::vector<argument_type> elements_to_transform(buffer_size_elements);
    std::vector<result_type> transformed_elements(buffer_size_elements);
  
    while(true) {
        input.read(reinterpret_cast<char*>(&elements_to_transform[0]), bytes_to_read);
        const std::streamsize bytes_read = input.gcount();
        if (bytes_read == 0) break;

        const std::streamsize elements_read = bytes_read / argument_type_size;
        const std::streamsize bytes_to_write = result_type_size * elements_read;
        std::transform(elements_to_transform.begin(),
                       elements_to_transform.begin() + elements_read,
                       transformed_elements.begin(),
                       op);
        output.write(reinterpret_cast<const char*>(&transformed_elements[0]), bytes_to_write);
    }   
}

struct Double2FloatConverter : public std::unary_function<double, float>
{
    result_type operator() (const argument_type& to_convert)
    {
        return static_cast<result_type>(to_convert);
    }
};

int main (int args, char** argv) 
{
    if (! (args == 4 || args == 3 ) ) 
    {
        std::cerr << "Wrong number of args" << std::endl << "usage: " << argv[0] 
             << " input_file output_file" << std::endl;
        exit(EXIT_FAILURE);
    }

    std::string input_file_name(argv[1]);
    std::ifstream input(input_file_name.c_str(), std::ios::binary);
    if(!input) 
    { 
        std::cerr << "Can't open input file \"" << input_file_name << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    std::string outputFileName(argv[2]);
    if (outputFileName == input_file_name)
    {
        std::cerr << "Can't write to the same file I am reading from\n";
        exit(EXIT_FAILURE);
    }
    std::ofstream output(outputFileName.c_str(), std::ios::binary);
    if(!output) 
    {
        std::cerr << "Can't open output file \"" << input_file_name.c_str() << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    const int buffer_size = 4*1024*1024;

    buffered_binary_stream_transform(input, output, Double2FloatConverter(), buffer_size);
}


Есть ли смысл передавать элементарные типы данных по константной ссылке, как это делается в Double2FloatConverter::operator() ?

Функтор наследует от unary_function и этого типа требует шаблон и я не знаю хорошо это или плохо. Выходит, что с этим требованием в buffered_binary_stream_transform нельзя использовать функтор, который не наследует от unary_function.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.