/*

    这是一个示例程序,使用了Dlib库的compress_stream和cmd_line_parser组件。

    这个示例实现了一个简单实用的命令行压缩程序。

    当使用-h选项时候,程序输出如下:

        使用: compress_stream_ex (-c|-d|-l) --in input_file --out output_file
选项:
-c 表示要执行压缩文件操作.
-d 表示要执行解压文件操作.
--in <arg> 此选项带一个参数,指定要压缩或解压的文件名称.
--out <arg> 此选项带一个参数,指定输出文件名称. 其他选项:
-h 显示帮助信息.
-l <arg> 设置压缩级别[1-3], 3是最大压缩,默认值是2. */ #include <dlib/compress_stream.h>
#include <dlib/cmd_line_parser.h>
#include <iostream>
#include <fstream>
#include <string> // 为要使用的compress_stream版本做一个typedef定义
typedef dlib::compress_stream::kernel_1da cs1;
typedef dlib::compress_stream::kernel_1ea cs2;
typedef dlib::compress_stream::kernel_1ec cs3; using namespace std;
using namespace dlib; int main(int argc, char** argv)
{
try
{
command_line_parser parser; // 首先,定义需要的命令行参数
// 添加 -c 选项,并给出描述信息
parser.add_option("c","表示要执行压缩文件操作.");
parser.add_option("d","表示要执行解压文件操作.");
// 添加需带一个参数的选项 --in
parser.add_option("in","此选项带一个参数,指定要压缩或解压的文件名称.",1);
// 添加需带一个参数的选项 --in
parser.add_option("out","此选项带一个参数,指定输出文件名称.",1); // 在下面代码中,使用parser.print_options()方法在屏幕上打印所有选项.
// 在添加这些选项之前,我们可以调用 set_group_name()将一些选项分组在一起。
// 通常,可以通过调用set_group_name()来创建多个分组。这里我们仅创建一个。
parser.set_group_name("其他选项");
parser.add_option("h","显示帮助信息.");
parser.add_option("l","设置压缩级别[1-3], 3是最大压缩,默认值是2.",1); // 现在,将解析命令行参数
parser.parse(argc,argv); // 现在,将使用parser(解析器)去验证命令行参数.
// 如果一下任意检验失败,将抛出异常。该异常包含一条消息,告诉错误原因. // 首先,需要检查一下,没有提供任何选项的命令行。
// 这需要定义一个数组,其中包含不应该多次出现的选项,然后调用check_one_time_options()
const char* one_time_opts[] = {"c", "d", "in", "out", "h", "l"};
parser.check_one_time_options(one_time_opts);
// 下面,检查用户是否同时提供 -c 和 -d 选项
parser.check_incompatible_options("c", "d"); // 下面检查 -l 选项,其参数应是1到3范围内的整数
// 也就是说,它可以通过dlib::string_assign转换到1、2或3。请注意,如果是要范围是1.0到3.0的
// 浮点数,则可以给出范围1.0到3.0。或者向check_option_arg_range()函数的template参数显示
// 提供一个float或double类型.
parser.check_option_arg_range("l", 1, 3); // 'l'选项是'c'选项的子选项。也就是说只能在压缩的时候选择压缩级别。
// 下面命令检查列出的子选项给出的时候,父选项是否存在。
const char* c_sub_opts[] = {"l"};
parser.check_sub_options("c", c_sub_opts); // 检查命令行中是否给出了-h选项
if (parser.option("h"))
{
// 显示所有命令行选项
cout << "使用: compress_stream_ex (-c|-d|-l) --in input_file --out output_file\n";
// 此函数打印出一个格式很好的列表,来展示parser具有所有选项
parser.print_options();
return 0;
} // 获取压缩级别选项值,如果没有则使用默认的2
int compression_level = get_option(parser,"l",2); // 确保提供了c或d两个选项之一
if (!parser.option("c") && !parser.option("d"))
{
cout << "命令行错误:\n 你必须指定 -c 或 -d 选项.\n";
cout << "\n使用 -h 选项查看更多信息." << endl;
return 0;
} string in_file;
string out_file; // 检查用户是否给出了输入文件名
// 如果是,在获取给定的文件名
if (parser.option("in"))
{
in_file = parser.option("in").argument();
}
else
{
cout << "命令行错误:\n 你必须指定一个输入文件.\n";
cout << "\n使用 -h 选项查看更多信息." << endl;
return 0;
} // 检查用户是否给出了输入文件名
// 如果是,在获取给定的文件名
if (parser.option("out"))
{
out_file = parser.option("out").argument();
}
else
{
cout << "命令行错误:\n 你必须指定一个输出文件.\n";
cout << "\n使用 -h 选项查看更多信息." << endl;
return 0;
} // 打开我们将要读取和写入的文件
ifstream fin(in_file.c_str(),ios::binary);
ofstream fout(out_file.c_str(),ios::binary); // 确保文件打开正确
if (!fin)
{
cout << "打开文件 " << in_file << " 出错.\n";
return 0;
} if (!fout)
{
cout << "创建文件 " << out_file << " 出错.\n";
return 0;
} // 现在执行实际的压缩或解压缩
if (parser.option("c"))
{
// 将压缩级别保存到输出文件
serialize(compression_level, fout); switch (compression_level)
{
case 1:
{
cs1 compressor;
compressor.compress(fin,fout);
}break;
case 2:
{
cs2 compressor;
compressor.compress(fin,fout);
}break;
case 3:
{
cs3 compressor;
compressor.compress(fin,fout);
}break;
}
}
else
{
// 从输入文件获取压缩级别
deserialize(compression_level, fin); switch (compression_level)
{
case 1:
{
cs1 compressor;
compressor.decompress(fin,fout);
}break;
case 2:
{
cs2 compressor;
compressor.decompress(fin,fout);
}break;
case 3:
{
cs3 compressor;
compressor.decompress(fin,fout);
}break;
default:
{
cout << "压缩文件有错误,无效的压缩级别。" << endl;
}break;
}
} }
catch (exception& e)
{
// 请注意,这将捕获所有cmd_line_parse_error异常并打印默认消息。
cout << e.what() << endl;
}
}
05-11 09:37