整套大数据学习资料(视频+笔记)百度网盘无门槛下载:http://www.edu360.cn/news/content?id=3377

4.2.1. codec

hadoop 花牛 6℃ 0评论

codec实现一种压缩-解压缩算法。在Hadoop中,一个对CompressionCodec接口的实现代表一个codec。例如,GzipCodec包装了gzip的压缩和解压缩算法。表4-2列举了 Hadoop实现的codec

表4-2. Hadoop 的压缩codec

压缩格式

HadoopCompressionCodec

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

LZ4

Org.apache.hadoop.io.compress.Lz4Codec

Snappy

Org.apache.hadoop.io.compress.SnappyCodec

LZO代码库拥有GPL许可,因而可能没有包含在Apache的发行版本中,因此,Hadoopcodec需要单独下载,代码库包含有修正的软件错误及其他一些工具。LzopCodec与lzop工具兼容,LzopCodec基本上是LZO格式的但包含额外的文件头,因此这通常就是你想要的。也有针对纯LZO格式的LzoCodec,并使用.Izo_deflate作为文件扩展名(类似于DEFLATE,但纯gzip并不包含文件头)。

通过CompressionCodec对数据流进行压缩和解

CompressionCodec包含两个函数,可以轻松用于压缩和解压缩数据。如 果要对写入输出数据流的数据进行压缩,可用createOutputStream(OutputStream out)方法在底层的数据流中对需要以压缩格式写入在此之前尚未压缩的数据新建一个CompressionOutputStream对象。相反,对输入数据流中读取的数据进行解压缩的时候,则调用createlnputStream (InputStream in)获取CompressionlnputStream,可通过该方法从底层 数据流读取解压缩后的数据。

CompressionOutputStreamCompressionlnputStream,类似于Java.util.zip.DeflaterOutputStream 和 java.util.zip.DeflaterlnputStream,只不过前两者能够重置其底层的压缩或解压缩方法,对于某些将部分数据流(section of data stream)压缩为单独数据块(block)的应用——例如SequenceFile,这个能力是非常重要的。

范例4-1显示了如何用API来压缩从标准输入中读取的数据并将其写到标准输出。

范例4-1.该程序压缩从标准输入读取的数据,然后将其写到标准输出

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)Reflectionlltils.newlnstance(codecClass, conf);
        CompressionOutputStream out = codec.createOutputStream(System.out);
        IOUtils.copyBytes(System.in, out, 4096, false);
        out.finish();
    }
}

该应用希望将符合CompressionCodec实现的完全合格名称作为第一个命令行参数。我们使用ReflectionUtils新建一个codec实例,并由此获得在 System.out上支持压缩的一个包裹方法。然后,对IOUtils对象调用copyBytes()方法将输入数据复制到输出,(输出由CompressionOutputStream对象压缩)。最后,我们对CompressionOutputStream对象调用finish()方法,要求压缩方法完成到压缩数据流的写操作,但不关闭这个数据流。我们可以用下面这行命令做一个测试,通过GzipCodec的StreamCompressor对象对字符串Text进行压缩,然后使用gunzip中从标准输入中对它进行读取并解压缩操作

% echo "Text" | hadoop StreamCompressor org.apache.hadoop.io.compress.GzipCodec | gunzip

Text

通过CompressionCodecFactory推断CompressionCodec

在读取一个压缩文件时,通常可以通过文件扩展名推断需要使用哪个codec。如果文件以.gz结尾,则可以用GzipCodec来读取,如此等等。表4-1为每一种压缩格式列举了文件扩展名。

通过使用其getCodec()方法,CompressionCodecFactory提供了一种可以将文件扩展名映射到一个CompressionCodec的方法,该方法取文件的Path对象作为参数。范例4-2所示的应用便使用这个特性来对文件进行解压缩。

范例4-2.该应用根据文件扩展名选取codec解压缩文件

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 = factony.getCodec(inputPath);
        if (codec == null) {
            System.err.printIn("No codec found for " + uri);
            System.exit(l);
        }
        String outputUri =CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
        InputStream in = null;
        OutputStream out = null;
        try{
            in = codec.createlnputstream(fs.open(inputPath));
            out = fs.create(new Path(outputUri));
            IOUtils.copyBytes(in, out, conf);
        } finally {
            IOUtils.closestream(in);
            IOUtils.closeStream(out);
        }
    }
}

一旦找到对应的codec,便去除文件扩展名形成输出文件名,这是通过CompressionCodecFactory对象的静态方法removeSuffix()来实现的。按照这种方法,一个名为file.gz的文件可以通过调用该程序压缩为名为file的文件:

% hadoop FileDecompressor file.gz

CompressionCodecFactory从io.compression.codecs属性(参见表 4.3)定义的一个列表中找到codec。在默认情况下,该列表列出了Hadoop提供的所有codec,所以只有在你拥有一个希望注册的定制codec(例如外部管理的LZO codec)时才需要加以修改。每个codec都知道自己默认的文件扩展名,因此CompressionCodecFactory可通过搜索注册的codec找到匹配指定文件扩展名的codec(如果有的话)。

表4-3.压缩codec的属性

属性名称

类型

默认值

描述

io.compression.codecs

逗号分隔 的类名

•org.apache.hadoop.io. compress.DefaultCodec

•org.apache.hadoop.io. compress.GzipCodec

•org.apache.hadoop.io. compress.Bzip2Codec

用于压缩/解压缩的各 个CompressionCodec类的列表

原生类库

为了性能,最好使用"原生"(native)类库来实现压缩和解压缩。例如,在一个测试中,使用原生gzip类库可以减少约一半的解压缩时间和约10%的压缩时间(与内置的Java实现相比)。表4-4给出了每种压缩格式的Java实现和原生类库实现。并非所有格式都有原生实现(如bzip2),有些则只有原生类库实现(如LZO)。

表4-4.压缩代码库的实现

压缩格式

是否有Java实现

否有原生实现

DEFLATE

gzip

bzip2

LZO

LZ4

Snappy

Hadoop本身包含有为32位和64位Linux构建的压缩代码库(位于lib/native目录)。其他平台,需要根据Hadoop英文维基页面(http://wiki.apache.org/hadoop/nativeHadoop)的指令编译代码库。

可以通过Java系统的java.library.path属性指定原生代码库。bin文件夹中的hadoop脚本可以帮你设置该属性,但如果不用这个脚本,则需要在应用中手动设置该属性。

默认情况下,Hadoop会根据自身运行的平台搜索原生代码库,如果找到相应的代码库就会自动加载。这意味着,你无需为了使用原生代码库而修改任何设置。但是,在某些情况下,例如调试一个压缩相关问题时,可能需要禁用原生代码库。将属性hadoop.native.lib的值设置成false即可,这可确保使用内置的Java代码库(如果有的话)。

 CodecPool

如果使用的是原生代码库并且需要在应用中执行大量压缩和解压缩操作, 可以考虑使用CodecPool,它支持反复使用压缩和解压缩,以分摊创建这些对象的开销。

范例4-3中的代码显示了 API函数,不过在这个程序中,它只新建了一个Compressor,并不需要使用压缩/解压缩池。

范例4-3.使用压缩池对读取自标准输入的数据进行压缩,然后将其写到标准输出

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.newlnstance(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);
        }
    }
}

在 codec 的重载方法 createOutputStream()中,对于指定的 CompressionCodec, 我们从池中获取一个Compressor实例。通过使用finally数据块,我们 在不同的数据流之间来回复制数据,即使出现IOException异常,也可以确保compressor可以返回池中。

转载请注明:全栈大数据 » 4.2.1. codec

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址