Самый быстрый способ записать большой вектор STL в файл с помощью STL

Я сделал одно подобное - но на основе взвешивания каждого цвета (на основе версии этого потока на C #)

function readableColour($bg){
    $r = hexdec(substr($bg,0,2));
    $g = hexdec(substr($bg,2,2));
    $b = hexdec(substr($bg,4,2));

    $contrast = sqrt(
        $r * $r * .241 +
        $g * $g * .691 +
        $b * $b * .068
    );

    if($contrast > 130){
        return '000000';
    }else{
        return 'FFFFFF';
    }
}

echo readableColour('000000'); // Output - FFFFFF

РЕДАКТИРОВАТЬ: Небольшая оптимизация Sqrt известен как дорогая математическая операция, которой, вероятно, пренебрегают в большинстве сценариев, но в любом случае этого можно избежать, если сделать что-то подобное.

function readableColour($bg){
    $r = hexdec(substr($bg,0,2));
    $g = hexdec(substr($bg,2,2));
    $b = hexdec(substr($bg,4,2));

    $squared_contrast = (
        $r * $r * .299 +
        $g * $g * .587 +
        $b * $b * .114
    );

    if($squared_contrast > pow(130, 2)){
        return '000000';
    }else{
        return 'FFFFFF';
    }
}

echo readableColour('000000'); // Output - FFFFFF

Он просто не применяет sqrt, вместо этого он усиливает желаемый обрезанный контраст на два, что намного дешевле в расчете

8
задан gnud 7 November 2009 в 16:11
поделиться

7 ответов

Имеется небольшая концептуальная ошибка с вашим вторым аргументом конструктора ostream_iterator . Это должен быть указатель NULL, если вам не нужен разделитель (хотя, к счастью для вас, это будет рассматриваться как таковой неявно), либо второй аргумент следует опустить.

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

Я думаю, если вы хотите использовать итераторы, возможно, вы могли бы попробовать ostreambuf_iterator .

Другое варианты могут включать использование метода write () (если он может обрабатывать такой большой вывод или, возможно, выводить его по частям) и, возможно, специфические для ОС функции вывода.

3
ответ дан 5 December 2019 в 05:34
поделиться

Поскольку ваши данные непрерывны в памяти (как сказал Чарльз), вы можете использовать низкоуровневый ввод-вывод. В Unix или Linux вы можете выполнять запись в файловый дескриптор. В Windows XP используйте дескрипторы файлов. (В XP это немного сложнее, но хорошо документировано в MSDN.)

XP немного забавляет буферизацию. Если вы запишете блок размером 1 ГБ в дескриптор, это будет медленнее, чем если бы вы разбили запись на меньшие размеры передачи (в цикле). Я обнаружил, что запись в 256 КБ наиболее эффективна. После того, как вы написали цикл, вы можете поиграть с ним и посмотреть, какой самый быстрый размер передачи.

2
ответ дан 5 December 2019 в 05:34
поделиться

Используйте метод записи на нем, в конце концов, он находится в оперативной памяти, и у вас непрерывная память .. Самый быстрый, а позже ищете гибкости? Избавьтесь от встроенной буферизации, подсказки последовательного ввода-вывода, потеряйте скрытые элементы итератора / утилиты, избегайте streambuf, когда можете, но испачкаетесь с помощью boost :: asio ..

-1
ответ дан 5 December 2019 в 05:34
поделиться

При таком большом объеме записываемых данных (~ 1 ГБ) вы должны писать в выходной поток напрямую, а не использовать итератор вывода. Поскольку данные в векторе хранятся непрерывно, это будет работать и должно быть намного быстрее.

ofstream outfile("nanocube.txt", ios::out | ios::binary);
outfile.write(&vs[0], vs.size());
23
ответ дан 5 December 2019 в 05:34
поделиться

Хорошо, я написал реализацию метода с циклом for, который записывает блоки данных размером 256 КБ (как предложил Роб) на каждой итерации, и результат составляет 16 секунд, поэтому проблема решена. Это моя скромная реализация, так что не стесняйтесь комментировать:

 void writeCubeToFile(const vector<char> &vs)
 {
     const unsigned int blocksize = 262144;
     unsigned long blocks = distance(vs.begin(), vs.end()) / blocksize;

     ofstream outfile("nanocube.txt", ios::out | ios::binary);

     for(unsigned long i = 0; i <= blocks; i++)
     {
         unsigned long position = blocksize * i;

         if(blocksize > distance(vs.begin() + position, vs.end())) outfile.write(&*(vs.begin() + position), distance(vs.begin() + position, vs.end()));
         else outfile.write(&*(vs.begin() + position), blocksize);
     }

     outfile.write("\0", 1);

     outfile.close();
}

Спасибо всем вам.

1
ответ дан 5 December 2019 в 05:34
поделиться

Если у вас другая структура, этот метод все еще действителен.

For example:

typedef std::pair<int,int> STL_Edge;
vector<STL_Edge> v;

void write_file(const char * path){
   ofstream outfile(path, ios::out | ios::binary);
   outfile.write((const char *)&v.front(), v.size()*sizeof(STL_Edge));
}

void read_file(const char * path,int reserveSpaceForEntries){
   ifstream infile(path, ios::in | ios::binary);
   v.resize(reserveSpaceForEntries);
   infile.read((char *)&v.front(), v.size()*sizeof(STL_Edge));
}
1
ответ дан 5 December 2019 в 05:34
поделиться

Вместо записи с помощью методов файлового ввода-вывода вы можете попытаться создать файл с отображением в память, а затем скопировать вектор в файл с отображением в память с помощью memcpy.

1
ответ дан 5 December 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: