Как осветляют комментарии, вы хотите загрузить байт двоичного файла в некоторый STL контейнер из char
- точнее, uint8_t
- и , чтобы сохранить такой контейнер обратно в двоичный файл.
Есть много способов сделать это, в том числе, как вы обнаружили, использование из std::basic_istream::read
и std::basic_ostream::write
, или std::istream_iterator
и std::ostream_iterator
.
Последний подход дает простейший код. Подход дает самый быстрый код, но проще для того, что, очевидно, будет простым прологовым и эпилоговым операциями вашей программы.
Вот соответствие пар функций шаблона, который будет соответственно:
Вернуть STL контейнер типа параметра Container
, заполненный байт-последовательность входного файла.
Скопируйте элементы контейнера STL типа параметра Container
в байтовую последовательность в выходной файл.
#include <fstream>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#include <cstdint>
template<class Container>
Container binary_load(std::string const & bin_file_name)
{
std::ifstream in(bin_file_name,std::ios::binary);
if (!in) {
throw std::runtime_error("Could not open \"" + bin_file_name +
"\" for reading");
}
std::noskipws(in); // PON 1
return Container(std::istream_iterator<std::uint8_t>(in),
std::istream_iterator<std::uint8_t>()); //PON 2
}
template<class Container>
void binary_save(Container && data, std::string const & bin_file_name)
{
std::ofstream out(bin_file_name,std::ios::binary);
if (!out) {
throw std::runtime_error("Could not open \"" + bin_file_name +
"\" for writing");
}
std::copy(data.begin(),data.end(),
std::ostream_iterator<std::uint8_t>(out,"")); // PON 3
}
Чтобы скомпилировать элементарный случай использования, добавьте это:
#include <vector>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string infile = argv[1];
string outfile = infile + ".saved";
auto data(binary_load<vector<std::uint8_t>>(infile));
binary_save(data,outfile);
return 0;
}
компилируется в C++ 11 или лучше. Полученная программа загружает файл, указанный вами в качестве первого аргумента командной строки , в std::vector<std::uint8_t>
, а затем только сохраняет этот вектор в файл с таким же именем с дополнительным расширением .saved
. Ваша программа, конечно же, загрузит один вектор и сохранит другой.
Points Of Примечание (PON):
Это утверждение потребного для информирования потока in
, что он должен черпать все байт, а не пропустить пробельные байт.
Это утверждение непосредственно строит населенную Container
из диапазона итератора [begin,end)
, таким образом, что каждый STL контейнер может быть построен. begin
итератора std::istream_iterator<char>(in)
является запуск из-потока итератора для in
и end
итератора std::istream_iterator<char>()
является истекшим потока итератора для каждого потока.
Данное заявление копирует последовательность байтов в последовательные позиции std::ostream_iterator<char>
, первоначально размещенных в начале out
. Аргумент конструктора итератора сообщает, что пустая строка (т. Е. Ничего) должна отделять последовательные выходные байты.
Эти функциональные шаблоны имеют несколько более общо, чем строго требуется:
Тип Container
, с которым вы призываете binary_load
не должен быть контейнер uint8_t
или даже прообразом тот же размер. Для этого требуется только тип контейнера, который может быть построен из диапазона итератора по последовательности uint8_t
.
Аналогично Container
тип, который вы вызываете binary_save
потребность быть только один, элементы которого имеют тип E
, который неявно конвертируемые в uint8_t
, с той оговоркой, что усечение будет происходить если вы waywardly выбрали для сохранения E
сек которые не были представлены в uint8_t
.
Так положить их вместе, никакого вреда не будет сделано, например, если вы заменить vector<uint8_t>
с vector<long>
в примере программы.
Конечно, если вы по ошибке вызывается либо шаблон функции с типом контейнера, которые не удовлетворяют требованиям шаблона из Container
, код будет не компилировать.
Продолжение комментариев OP в
Могу ли я использовать неподписанные символ вместо [из uint8_t]?
Да, uint8_t
почти неизбежно определяются как unsigned char
ваш компилятора (ов), а также любой 8-битный типа интегрального типа будет делать. uint8_t
только наиболее четко говорит «байт».Если вы хотели для дальнейшего параметрирования функции шаблона относительно «байт» типа, вы могли бы сделать так, как:
...
#include <type_traits>
template<class Container, typename Byte = std::uint8_t>
Container binary_load(std::string const & bin_file_name) {
static_assert(sizeof(Byte) == 1,"Size of `Byte` must be 1");
// `std::uint8_t` becomes `Byte`
...
}
template<class Container, typename Byte = std::uint8_t>
void binary_save(Container && data, std::string const & bin_file_name) {
static_assert(sizeof(Byte) == 1,"Size of `Byte` must be 1");
// `std::uint8_t` becomes `Byte`
...
}
Что касается правого расширения файла для Хаффмана закодированы файлы, нет никакого стандартного де-факто. Выберите то, что вам нравится.
И если вам не требуется использовать MS VC10 (с патчей поддержки C++ 11), то для вашей версии консоли вам не понадобится . Bang up-to-date GCC toolchains are freely available for Windows и с поддержкой IDEs: CodeLite, Code::Blocks
Почему вы предпочитаете std: list? – DaveyLaser
Взгляните на это: [чтение файла в вектор с помощью итераторов [(http://stackoverflow.com/questions/3795326/using-insert-iterators-when-reading-from-file) –
@laser_wizard std :: list has случайный доступ, который мне помог в других проблемах. Я знаю, что файлы записываются последовательно, но std :: list kinda стал моим основным преимуществом. Я знаю, что мы должны измениться в соответствии с тем, что подходит для программы, но это работало для меня в большинстве случаев, поэтому я использую его. Почему вы спрашиваете? Не подходит ли это в этом случае? – WDRKKS