WDR*_*KKS 1 c++ fstream stl ifstream ofstream
我需要以二进制模式读取文件并将字节作为十六进制值存储在任何STL容器中(最好是std :: list).后来我需要将它们写回文件,也是二进制模式.所以,我宣布,
typedef unsigned char BYTE;
std::ifstream File("File_Name", std::ios::binary);
std::list<BYTE> File_Bytes;
Run Code Online (Sandbox Code Playgroud)
通过所有的搜索,我理解了一些事情.可以使用std :: istream :: read()或std :: istreambuf_iterator进行读取(我可能非常错误.请纠正我.)而read()函数只将char*作为内存中存储字节的参数输入流的大小.
如果我必须将文件中的字节读入BYTE列表并再次使用istream和ostream分别从BYTE列表写入文件,我将如何执行此操作?请为我澄清一下.谢谢.
注意:这实际上是用于霍夫曼编码器/解码器,我需要在程序内部压缩和解压缩,并将解压缩的位写为输出文件.这是为了验证压缩的无损性和程序的正确性.另外,任何人都可以告诉我如何将编码的二进制位写入文件以及编码的Huffman文件具有哪些文件扩展名?非常感谢你.
正如注释所阐明的那样,您希望将二进制文件的字节加载到某个STL容器中char- 或者更准确地说,uint8_t- 并将这样的容器保存回二进制文件.
有很多方法可以做到这一点,包括你发现的,使用std::basic_istream::read
和std::basic_ostream::write,或者std::istream_iterator
和std::ostream_iterator.
后一种方法产生了最简单的代码.该fread/ fwrite方法产生速度最快的代码,但更简单的是什么显然将是你的程序仅仅是序幕和尾声操作更好.
这是一对匹配的模板函数,分别为:
返回参数类型的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
}
Run Code Online (Sandbox Code Playgroud)
要编译基本用例,请附加:
#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;
}
Run Code Online (Sandbox Code Playgroud)
这可以编译为C++ 11或更高版本.生成的程序将您指定的文件作为其第一个命令行参数加载到a中std::vector<std::uint8_t>,然后将该向量保存到具有附加扩展名的同名文件中.saved.当然,您的程序将加载一个向量并保存另一个向量.
注意事项(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但需要注意的是,如果您无意中选择保存任何E不可表示的内容,则会发生截断uint8_t.
因此,将这些放在一起,不会造成任何伤害,例如,如果您在示例程序中替换vector<uint8_t>它vector<long>.
当然,如果您错误地使用不满足模板要求的容器类型调用任一函数模板
Container,则代码将无法编译.
继续OP的评论
我可以使用unsigned char代替[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`
...
}
Run Code Online (Sandbox Code Playgroud)
关于霍夫曼编码文件的正确文件扩展名,没有事实上的标准.选择你喜欢的.
除非您需要为您的控制台版本使用MS VC10(支持补丁C++ 11),否则无需使用.Bang最新的GCC工具链可免费用于Windows和支持IDE:CodeLite,Code :: Blocks
| 归档时间: |
|
| 查看次数: |
5241 次 |
| 最近记录: |