Hadoop 小文件处理 SequcenceFile 可以直接定位到某个小文件 info

SequenceFile概述

SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。

在SequenceFile文件中,每一个key-value被看做是一条记录(Record),因此基于Record的压缩策略,SequenceFile文件可支持三种压缩类型(SequenceFile.CompressionType):

  1. NONE: 对records不进行压缩;
  2. RECORD: 仅压缩每一个record中的value值; Record压缩率低,
  3. BLOCK: 将一个block中的所有records压缩在一起;  一般建议使用BLOCK压缩。

思想:sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。 同时对这些小文件的位置信息构建索引。不过,这类解决方案还涉及到Hadoop的另一种文件格式——MapFile文件。SequenceFile文件并不保证其存储的key-value数据是按照key的某个顺序存储的,同时不支持append操作。

代码思路:定义方法用来添加小文件的路径,给定路径是文件夹,则遍历文件夹,将子文件夹中的文件都放入smallFilePaths,给定路径是文件,则把文件的路径放入smallFilePaths,把smallFilePaths的小文件遍历读取,然后放入合并的sequencefile容器中,遍历读取小文件,逐个写入sequencefile,把文件路径作为key,文件内容做为value,放入到sequencefile中,读取大文件中的小文件 

package com.lj.small;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
 
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.Reader;
import org.apache.hadoop.io.SequenceFile.Writer;
import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class MergeSmallFilesToSequenceFile {
	private static Logger logger = LoggerFactory.getLogger(MergeSmallFilesToSequenceFile.class);
	private Configuration configuration = new Configuration();
	private List smallFilePaths = new ArrayList();
	
	//定义方法用来添加小文件的路径
	public void addInputPath(String inputPath) throws Exception{
		File file = new File(inputPath);
		//给定路径是文件夹,则遍历文件夹,将子文件夹中的文件都放入smallFilePaths
		//给定路径是文件,则把文件的路径放入smallFilePaths
		if(file.isDirectory()){
			File[] files = FileUtil.listFiles(file);
			for(File sFile:files){
				smallFilePaths.add(sFile.getPath());
				logger.info("添加小文件路径:" + sFile.getPath());
			}
		}else{
			smallFilePaths.add(file.getPath());
			logger.info("添加小文件路径:" + file.getPath());
		}
	}
	//把smallFilePaths的小文件遍历读取,然后放入合并的sequencefile容器中
	public void mergeFile() throws Exception{
		Writer.Option bigFile = Writer.file(new Path("/bigfile.seq"));
		Writer.Option keyClass = Writer.keyClass(Text.class);
		Writer.Option valueClass = Writer.valueClass(BytesWritable.class);
		//构造writer
		Writer writer = SequenceFile.createWriter(configuration, bigFile, keyClass, valueClass);
		//遍历读取小文件,逐个写入sequencefile
		Text key = new Text();
		for(String path:smallFilePaths){
			File file = new File(path);
			long fileSize = file.length();//获取文件的字节数大小
			byte[] fileContent = new byte[(int)fileSize];
			FileInputStream inputStream = new FileInputStream(file);
			inputStream.read(fileContent, 0, (int)fileSize);//把文件的二进制流加载到fileContent字节数组中去
			String md5Str = DigestUtils.md5Hex(fileContent);
			logger.info("merge小文件:"+path+",md5:"+md5Str);
			key.set(path);
			//把文件路径作为key,文件内容做为value,放入到sequencefile中
			writer.append(key, new BytesWritable(fileContent));
		}
		writer.hflush();
		writer.close();
	}
	//读取大文件中的小文件
	public void readMergedFile() throws Exception{
		Reader.Option file = Reader.file(new Path("/bigfile.seq"));
		Reader reader = new Reader(configuration, file);
		Text key = new Text();
		BytesWritable value = new BytesWritable();
		while(reader.next(key, value)){
			byte[] bytes = value.copyBytes();
			String md5 = DigestUtils.md5Hex(bytes);
			String content = new String(bytes, Charset.forName("GBK"));
			logger.info("读取到文件:"+key+",md5:"+md5+",content:"+content);
		}
	}
	
	public static void main(String[] args) throws Exception {
		MergeSmallFilesToSequenceFile msf = new MergeSmallFilesToSequenceFile();
		//合并小文件
//		msf.addInputPath("D:\\smallfiles");
//		msf.mergeFile();
		//读取大文件
		msf.readMergedFile();
	}
}

 

你可能感兴趣的:(大数据)