认识org.apache.hadoop.io.compress解码器/编码器
编码器和解码器用以执行压缩解压算法。在Hadoop里,编码/解码器是通过一个压缩解码器接口实现的。因此,例如,GzipCodec封装了gzip压缩的压缩和解压算法。下表列出了Hadoop可用的编码/解码器。
压缩格式 | Hadoop压缩编码/解码器 |
DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
gzip | org.apache.hadoop.io.compress.GzipCodec |
bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compression.lzo.LzopCodec |
下例中说明了如何使用API来压缩从标谁输入读取的数据及如何将它写到标准输出:
public class StreamCompressor
{
public static void main(String[] args) throws Exception
{
String codecClassname = args[0];
Class<?> codecClass = Class.forName(codecClassname);
Configuration conf = new Configuration();
CompressionCodec codec = (CompressionCodec)
ReflectionUtils.newInstance(codecClass, conf);
CompressionOutputStream out = codec.createOutputStream(System.out);
IOUtils.copyBytes(System.in, out, 4096, false);
out.finish();
}
}
|
% echo "Text" | hadoop StreamCompressor org.apache.hadoop.io.compress.GzipCodec
| gunzip -
Text
|
在阅读一个压缩文件时,我们通常可以从其扩展名来推断出它的编码/解码器。以.gz结尾的文件可以用GzipCodec来阅读,如此类推。每个压缩格式的扩展名均以下表所示:
压缩格式 | 工具 | 算法 | 文件扩展名 | 多文件 | 可分割性 |
DEFLATEa | 无 | DEFLATE | .deflate | 不 | 不 |
gzip | gzip | DEFLATE | .gz | 不 | 不 |
ZIP | zip | DEFLATE | .zip | 是 | 是,在文件范围内 |
bzip2 | bzip2 | bzip2 | .bz2 | 不 | 是 |
LZO | lzop | LZO | .lzo | 不 | 是 |
CompressionCodecFactory提供了getCodec()方法,从而将文件扩展名映射到相应的CompressionCodec。此方法接受一个Path对象。下面的例子显示了一个应用程序,此程序便使用这个功能来解压缩文件。
public class FileDecompressor {
public static void main(String[] args) throws Exception {
String uri = args[0];
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
Path inputPath = new Path(uri);
CompressionCodecFactory factory = new CompressionCodecFactory(conf);
CompressionCodec codec = factory.getCodec(inputPath);
if (codec == null) {
System.err.println("No codec found for " + uri);
System.exit(1);
}
String outputUri =
CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
InputStream in = null;
OutputStream out = null;
try {
in = codec.createInputStream(fs.open(inputPath));
out = fs.create(new Path(outputUri));
IOUtils.copyBytes(in, out, conf);
} finally {
IOUtils.closeStream(in);
IOUtils.closeStream(out);
}
}
}
% hadoop FileDecompressor
file
.gz
属性名 | 类型 | 默认值 | 描述 |
io.compression.codecs | 逗号分隔的类名 | org.apache.hadoop.io. compress.DefaultCodec, org.apache.hadoop.io. compress.GzipCodec, org.apache.hadoop.io. compress.Bzip2Codec | 用于压缩/解压的CompressionCodec列表 |
表4-3
考虑到性能,最好使用一个本地库(native library)来压缩和解压。例如,在一个测试中,使用本地gzip压缩库减少了解压时间50%,压缩时间大约减少了10%(与内置的Java实现相比 较)。表4-4展示了Java和本地提供的每个压缩格式的实现。井不是所有的格式都有本地实现(例如bzip2压缩),而另一些则仅有本地实现(例如 LZO)。
压缩格式 | Java实现 | 本地实现 |
DEFLATE | 是 | 是 |
gzip | 是 | 是 |
bzip2 | 是 | 否 |
LZO | 否 | 是 |
Hadoop带有预置的32位和64位Linux的本地压缩库,位于库/本地目录。对于其他平台,需要自己编译库,具体请参见Hadoop的维基百科http://wiki.apache.org/hadoop/NativeHadoop。
本地库通过Java系统属性java.library.path来使用。Hadoop的脚本在bin目录中已经设置好这个属性,但如果不使用该脚本,则需要在应用中设置属性。
默认情况下,Hadoop会在它运行的平台上查找本地库,如果发现就自动加载。这意味着不必更改任何配置设置就可以使用本地库。在某些情况下,可能 希望禁用本地库,比如在调试压缩相关问题的时候。为此,将属性hadoop.native.lib设置为false,即可确保内置的Java等同内置实现 被使用(如果它们可用的话)。
CodecPool(压缩解码池)
如果要用本地库在应用中大量执行压缩解压任务,可以考虑使用CodecPool,从而重用压缩程序和解压缩程序,节约创建这些对象的开销。
下例所用的API只创建了一个很简单的压缩程序,因此不必使用这个池。此应用程序使用一个压缩池程序来压缩从标准输入读入然后将其写入标准愉出的数据:
public class PooledStreamCompressor
{
public static void main(String[] args) throws Exception
{
String codecClassname = args[0];
Class<?> codecClass = Class.forName(codecClassname);
Configuration conf = new Configuration();
CompressionCodec codec = (CompressionCodec)
ReflectionUtils.newInstance(codecClass, conf);
Compressor compressor = null;
try {
compressor = CodecPool.getCompressor(codec);
CompressionOutputStream out = codec.createOutputStream(System.out, compressor);
IOUtils.copyBytes(System.in, out, 4096, false);
out.finish();
} finally
{
CodecPool.returnCompressor(compressor);
}
}
}
我 们从缓冲池中为指定的CompressionCodec检索到一个Compressor实例,codec的重载方法 createOutputStream()中使用的便是它。通过使用finally块,我们便可确保此压缩程序会被返回缓冲池,即使在复制数据流之间的字 节期间抛出了一个IOException。