hadoop合并小文件的一些方法

小文件: 是那些size比HDFS的block size(默认128M)小的多的文件
因为: 任何一个文件,目录和block,在HDFS中都会被表示为一个object存储在namenode的内存中,每一个object占用150 bytes的内存空间。
如果有10million个文件,每一个文件对应一个block,那么就将要消耗namenode 3G的内存来保存这些block的信息。文件在大的话,对内存要求会更多。
1 合并小文件方式:
a) 应用程序自己控制, 缺点是: 各类数据都混合在一起,以后无法区分

import java.io.File;  
import java.io.FileInputStream;  
import java.net.URI;  
import java.util.List;  
  
import org.apache.commons.io.IOUtils;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FSDataOutputStream;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
  
  
public class CopyOfApp1 {  
  
    public static void main(String[] args) throws Exception {  
        // 0 初始化filesystem客户端  
        final Configuration conf = new Configuration();  
        final FileSystem fileSystem = FileSystem.get(new URI("hdfs://chinadaas109:9000/"), conf);  
      
        System.out.println(fileSystem);  
        final Path path = new Path("/combinedfile");  
        final FSDataOutputStream create = fileSystem.create(path); // hdfs创建目标文件   
        final File dir = new File("/data/input");  // 将此文件夹下的内容写到hdfs path中  
        for(File fileName : dir.listFiles()) {  
            System.out.println(fileName.getAbsolutePath());  
            final FileInputStream fileInputStream = new FileInputStream(fileName.getAbsolutePath());  
            final List<String> readLines = IOUtils.readLines(fileInputStream);  
            for (String line : readLines) {  
                create.write(line.getBytes());    
            }  
            fileInputStream.close();  
        }  
        create.close();   
  
    } 

b) archive,归档历史小文件
HAR文件是通过在HDFS上构建一个层次化的文件系统来工作。
一个HAR文件是通过hadoop的archive命令来创建,而这个命令实际上也是运行了一个MapReduce任务来将小文件打包成HAR。
对于client端来说,使用HAR文件没有任何影响。所有的原始文件都(usinghar://URL)。但在HDFS端它内部的文件数减少了。
过HAR来读取一个文件并不会比直接从HDFS中读取文件高效,
而且实际上可能还会稍微低效一点,因为对每一个HAR文件的访问都需要完成两层index文件的读取和文件本身数据的读取。
并且尽管HAR文件可以被用来作为MapReducejob的input,但是并没有特殊的方法来使maps将HAR文件中打包的文件当作一个HDFS文件处理。
创建文件hadooparchive-archiveNamexxx.har-p/src/dest
c) sequence file/map file
sequence file:filename作为key,file contents作为value
比如10000个100KB的文件,可以写一个程序来将这些小文件写入到一个单独的 SequenceFile中。
可以在一个streaming fashion(directly or using mapreduce)中来使用这个sequenceFile。
并且,SequenceFiles也是splittable的,所以mapreduce 可以break them into chunks,并且分别的被独立的处理。
这种方式还支持压缩。

import java.io.IOException;  
  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.Path;  
import org.apache.hadoop.io.IOUtils;  
import org.apache.hadoop.io.SequenceFile;  
import org.apache.hadoop.io.SequenceFile.CompressionType;  
import org.apache.hadoop.io.SequenceFile.Reader;  
import org.apache.hadoop.io.SequenceFile.Writer;  
import org.apache.hadoop.io.Text;  
  
public class TestSequenceFile {  
  
    /** 
     * @param args 
     * @throws IOException 
     */  
    public static void main(String[] args) throws IOException {  
        // // TODO Auto-generated method stub  
         Configuration conf = new Configuration();  
         Path seqFile = new Path("/test/seqFile2.seq");  
         // Writer内部类用于文件的写操作,假设Key和Value都为Text类型  
         SequenceFile.Writer writer = SequenceFile.createWriter(conf,  
         Writer.file(seqFile), Writer.keyClass(Text.class),  
         Writer.valueClass(Text.class),  
         Writer.compression(CompressionType.NONE));  
  
         // 通过writer向文档中写入记录  
         writer.append(new Text("key"), new Text("value"));  
          
         IOUtils.closeStream(writer);// 关闭write流  
         // 通过reader从文档中读取记录  
         SequenceFile.Reader reader = new SequenceFile.Reader(conf,  
         Reader.file(seqFile));  
         Text key = new Text();  
         Text value = new Text();  
         while (reader.next(key, value)) {  
         System.out.println(key);  
         System.out.println(value);  
         }  
         IOUtils.closeStream(reader);// 关闭read流  
  
          
    }  
  
} 

参考:https://www.iteye.com/blog/chengjianxiaoxue-2259523

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值