• hadoop2.x之IO:压缩和解压缩


    文件压缩可以降低存储需要的空间,并且在传输过程中加快传输速度。因此对于大量数据的处理时,压缩是十分重要的。我们考虑一下Hadoop在文件中的压缩用法。
    有许多压缩方式,如下:

    压缩格式 工具 算法 文件拓展名 是否可切分
    DEFLATE DEFLATE .deflate
    Gzip gzip DEFLATE .gz
    bzip2 bzip2 bzip2 bz2
    LZO lzop LZO .lzo
    LZ4 LZ4 .lz4
    Snappy Snappy .snappy

    压缩主要考虑时间和速度,在上面的三种压缩工具中都提供了对压缩时间和压缩空间的调整参数。-1是为优化压缩速度,-9是优化压缩空间,1~9中间其他的参数介于二者之间。

    另外不同的压缩有着不同的特性,

    • bzip2压缩能力强,但压缩时间慢。他的解压较快
    • gzip压缩能力和压缩时间介于bzip2和lzop之间
      因此不同的情况有着不同的使用。

    1. 使用CompressionCodec接口实现压缩和解压缩

    在Hadoop中CompressionCodec接口定义了压缩和解压缩的方法。其包含许多具体的实现。
    实现如下:

    压缩格式 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

    CompressionCodec中包含两个函数用于压缩和解压:

    • createOutputStream(OutputStream out)压缩out中的内容,并返回一个CompressionOutputStream对象来包含压缩结果。
    • createInputStream(InputStream in)解压in中的内容,并返回一个CompressionInputStream对象来包含解压结果。

    2. 压缩程序

    编写一个压缩程序:

    import java.io.IOException;
    import java.net.URI;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FSDataInputStream;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.io.compress.CompressionCodec;
    import org.apache.hadoop.io.compress.CompressionOutputStream;
    import org.apache.hadoop.io.compress.GzipCodec;
    import org.apache.hadoop.util.ReflectionUtils;
    
    public class GZipCodec {
    
    	public static void main(String[] args) throws IOException {
    		String srcUrl = args[0];		
    		String targetUrl = args[1];	
    		
    		Configuration conf = new Configuration();
    		FileSystem inFs = FileSystem.get(URI.create(srcUrl),conf);
    		FileSystem outFs = FileSystem.get(URI.create(targetUrl),conf);
    		
    		CompressionCodec codec = ReflectionUtils.newInstance(GzipCodec.class,conf);
    		FSDataInputStream inputStream = inFs.open(new Path(srcUrl));
    		CompressionOutputStream outputStream = codec.createOutputStream(outFs.create(new Path(targetUrl)));
    		
    		IOUtils.copyBytes(inputStream, outputStream, 4096,false);
    		outputStream.finish();
    		IOUtils.closeStream(outputStream);
    		IOUtils.closeStream(inputStream);
    		
    		System.out.println("输入文件的大小"+inFs.getFileStatus(new Path(srcUrl)).getLen()+"b");
    		System.out.println("输出文件的大小"+outFs.getFileStatus(new Path(targetUrl)).getLen()+"b");
    		System.out.printf("压缩率为%.2f%%
    ",100*(1.0*outFs.getFileStatus(new Path(targetUrl)).getLen()/inFs.getFileStatus(new Path(srcUrl)).getLen()));
    	}
    }
    

    在hadoop下运行:

    [grid@tiny01 input]$  hadoop GZipCodec file:///home/grid/input/data.txt file:///home/grid/input/data.gz
    17/07/28 01:49:03 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java 
    classes where applicable
    输入文件的大小49252b
    输出文件的大小2362b
    压缩率为4.80%
    

    可以看到压缩的还是很不错的。我们使用linux的gzip命令压缩一下

    [grid@tiny01 input]$ md5sum data.txt
    e8d882c5b4f4c8d6952d8a88a4d65c52  data.txt
    [grid@tiny01 input]$ gzip -d data.gz
    [grid@tiny01 input]$ md5sum data
    e8d882c5b4f4c8d6952d8a88a4d65c52  data
    

    我们可以看到压缩的和解压的是同一个文件。(md5sum在cyrus-sasl-md5包下)

    关于

    17/07/28 01:49:03 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
    

    是因为Java默认查询原生类库(native),如果找到则会自动加载,如果没有找到就会出现这个警告。

    3. 解压程序

    import java.io.IOException;
    import java.net.URI;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FSDataInputStream;
    import org.apache.hadoop.fs.FSDataOutputStream;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.io.compress.CompressionCodec;
    import org.apache.hadoop.io.compress.CompressionInputStream;
    import org.apache.hadoop.io.compress.CompressionOutputStream;
    import org.apache.hadoop.io.compress.GzipCodec;
    import org.apache.hadoop.util.ReflectionUtils;
    
    public class GZipDCodec {
    
    	public static void main(String[] args) throws IOException {
    		String srcUrl = args[0];		
    		String targetUrl = args[1];	
    		
    		Configuration conf = new Configuration();
    		FileSystem inFs = FileSystem.get(URI.create(srcUrl),conf);
    		FileSystem outFs = FileSystem.get(URI.create(targetUrl),conf);
    		
    		CompressionCodec codec = ReflectionUtils.newInstance(GzipCodec.class,conf);
    		FSDataOutputStream outputStream = outFs.create(new Path(targetUrl));
    		CompressionInputStream inputStream = codec.createInputStream(inFs.open(new Path(srcUrl)));
    		
    		IOUtils.copyBytes(inputStream, outputStream, 4096,false);
    
    		outputStream.close();
    		inputStream.close();
    		
    		System.out.println("输入文件的大小"+inFs.getFileStatus(new Path(srcUrl)).getLen()+"b");
    		System.out.println("输出文件的大小"+outFs.getFileStatus(new Path(targetUrl)).getLen()+"b");
    		System.out.printf("解压率为%.2f%%
    ",100*(1.0*outFs.getFileStatus(new Path(targetUrl)).getLen()/inFs.getFileStatus(new Path(srcUrl)).getLen()));
    	}
    }
    
    

    运行可得

    [grid@tiny01 input]$ ll
    总用量 64
    -rw-r--r--. 1 grid grid  2362 7月  28 04:55 data.gz
    -rw-rw-r--. 1 grid grid 49252 7月  27 23:46 data.txt
    -rw-r--r--. 1 grid grid     8 7月  27 04:03 word2.txt
    -rw-rw-r--. 1 grid grid    11 6月  25 18:31 word.txt
    
    [grid@tiny01 input]$ hadoop GZipDCodec file:///home/grid/input/data.gz file:///home/grid/input/data1.txt
    17/07/28 16:34:01 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
    17/07/28 16:34:01 INFO compress.CodecPool: Got brand-new decompressor [.gz]
    输入文件的大小2362b
    输出文件的大小49252b
    解压率为2085.18%
    
    [grid@tiny01 input]$ ll
    总用量 116
    -rw-r--r--. 1 grid grid 49252 7月  28 16:34 data1.txt
    -rw-r--r--. 1 grid grid  2362 7月  28 04:55 data.gz
    -rw-rw-r--. 1 grid grid 49252 7月  27 23:46 data.txt
    -rw-r--r--. 1 grid grid     8 7月  27 04:03 word2.txt
    -rw-rw-r--. 1 grid grid    11 6月  25 18:31 word.txt
    

    4.根据文件拓展名推测解压方式
    hadoop还提供了一个通过拓展名猜测压缩算法的方法:CompressionCodecFactory类中的getCodec()方法。

    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.URI;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.io.compress.CompressionCodec;
    import org.apache.hadoop.io.compress.CompressionCodecFactory;
    
    
    public class DefaultDCodec {
    	
    	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("没有找到压缩方式:"+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);
    		} catch (Exception e) {
    			IOUtils.closeStream(in);
    			IOUtils.closeStream(out);
    		}
    		
    	}
    
    }
    

    运行结果:

    [grid@tiny01 input]$ ll
    总用量 64
    -rw-r--r--. 1 grid grid  2362 7月  28 04:55 data.gz
    -rw-rw-r--. 1 grid grid 49252 7月  27 23:46 data.txt
    -rw-r--r--. 1 grid grid     8 7月  27 04:03 word2.txt
    -rw-rw-r--. 1 grid grid    11 6月  25 18:31 word.txt
    [grid@tiny01 input]$ hadoop DefaultDCodec file:///home/grid/input/data.gz
    17/07/28 21:48:19 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
    17/07/28 21:48:20 INFO compress.CodecPool: Got brand-new decompressor [.gz]
    [grid@tiny01 input]$ ll
    总用量 116
    -rw-r--r--. 1 grid grid 49252 7月  28 21:48 data
    -rw-r--r--. 1 grid grid  2362 7月  28 04:55 data.gz
    -rw-rw-r--. 1 grid grid 49252 7月  27 23:46 data.txt
    -rw-r--r--. 1 grid grid     8 7月  27 04:03 word2.txt
    -rw-rw-r--. 1 grid grid    11 6月  25 18:31 word.txt
    

    5.参考资料
    [1] Hadoop:The Definitive Guide,Third Edition, by Tom White. Copyright 2013 Tom White,978-1-449-31152-0

  • 相关阅读:
    预习非数值数据的编码方式
    预习原码补码
    C语言||作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言|作业12—学期总结
    C语言|博客作业11
    第三章预习
  • 原文地址:https://www.cnblogs.com/erygreat/p/7352455.html
Copyright © 2020-2023  润新知