2021-07-05 自定义InputFormat案例 处理大量小文件的场景

1.``smallFileInputfromat类

看一下整体代码
首先我们根据需求。你要定义一个 Fire input format要先继承一个 Fireinputformat。继承 File input format需要你实现一个record read的方法。你把它继承之后,你就需要实现。 Record reader方法。
由于我们刚才分析要对小文件进行统一处理,所以我们设置了不可分割。如果他进行分割,他就不能够进行统一处理了,所以我们把它设置成统一处理。
然后呢,你这里需要自定义一个 Record reader对象。所以我们给他自定义一个 Record reader对象然后来继承 Record reader,然后呢,我们把这个 Split和context信息给他传了进去,嗯,最后返回 Record reader对象。
然后file input format就已经完成了

在这里插入代码片package com.jinghang.class30.smallFile;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.JobContext;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import java.io.IOException;

public class smallFileInputfromat extends FileInputFormat<Text,Text> {
    @Override
    protected boolean isSplitable(JobContext context, Path filename) {
        return false;
    }

    @Override
    public RecordReader<Text, Text> createRecordReader(InputSplit Split, TaskAttemptContext Context) throws IOException, InterruptedException {
//        return null;
        smallFileRecordReader reader = new smallFileRecordReader();
        reader.initialize(Split,Context);
        return reader;
    }
}



















2.smallFileRecordReader 类

File input format完成之后,我们就开始自己来写这Record reader对象,然后继承之后发现它导入了几个方法:
初始化方法 ,
返回下一组kv,
获取下一个Key,
获取下一个value,
显示程序进程,
关闭程序,

然后我们处理的时候,对于这一块显示程序进程,文件要么读完,要么没读完。
所以我们设置一个布尔值,默认他是没有读。
然后我们在显示程序进程那里反馈说,如果读完返回0没有读完,返回1。

然后在初始化方法中,
把inputsplit对象 Split转化为 FileSplit,就是把切片信息转化为文件切片信息,
然后通过file split.getPath()就获取到了文件路径,

然后获取的文件路径之后,我们开始下一步操作,首先先判断一下我们文件有没有读 ,
如果没有读,我们开始我们的逻辑,我们的默认值是true,就是没有读,
首先我们上面已经获取到了文件的路径,这时候Path.get name(),也可以获取到文件里。这个时候我们 Key就已经有了。

我们value值是文件内容,然后这样呢,我们就学到了一个新的东西,一个固定的用法。就是已知一个文件名和文件路径,然后再通过一个装箱的方法。 Buffer reader里面装着input stream reader, Input stream reader里面又装着fireinputStream,通过这种装箱的方法,最终拿到了文件的所有内容就是 Buffered reader

然后我们定义一个line接收它的每行内容,
定义一个新的Stringbuffer接收新的每行内容,
然后门的循环
Buffer reader每次读取一行。然后把它复制给line然后通过Stringutils来判断他是不是读完。如果没有读完的话,我每次都去银行把它加到StringBuffer里面,然后这个循环走完,
Stringbuffer里面就有了所有的文件内容。然后把它写到v里面, 接着全部读完之后,把他的状态改为 False, Return true返回,最终输入结果。
最后。 Return false。
这里的return false是接着判断,还有内容的话我可以接着判断。

这个写完之后获取下一个K。

在写完之后获取下一个value。

然后获取进程,要么成功要么失败。

关闭程序可以不用写。
然后record reader主体的代码写完。
我们写了一下Driver程序

在这里插入代码片
package com.jinghang.class30.smallFile;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class smallFileRecordReader extends RecordReader<Text, Text> {
    // 定义一个变量表示 进程是否结束
    private boolean isNotRead = true;
    //定义一个变量表示 文件路径名
    private Path path = null;
    //定义一个变量 key 表示 文件路径名+文件名
    private Text key = new Text();
    //定义一个变量 v表示 文件内容
    private Text v = new Text();

    //初始化方法
    @Override
    public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
        //将切片信息转换为文件切片信息
        FileSplit file = (FileSplit) split;
        //拿到文件路径
        path = file.getPath();

    }

    //返回下一组KV对
    @Override
    public boolean nextKeyValue() throws IOException, InterruptedException {
        if (isNotRead) {
            //如果还没有读取文件,则开始处理文件
            //key 文件路径和文件名 value 是文件内容
   //1.获取key值
    key.set(path + path.getName());//path表示文件路径,path.getName()表示文件名

   //2.。获取value值
            //2.1获取文件内容的固定用法
     BufferedReader bufferedReader = new BufferedReader(new
    InputStreamReader(new FileInputStream(path.toString().replace("file:/",""))));

     //2.2读取行内容
    String line;//定义一个变量接收value值每一行数据
    //定义一个StringBuffer接收bufferedReader里面所有内容
   StringBuffer stringBuffer = new StringBuffer();

    //StringUtils.isNotEmpty判断内容是否为空的工具
   //line = bufferedReader.readLine()每次读取一行内容赋值给line
   //stringBuffer.append(line+"======") 把每一行内容追加到stringBuffer,
            // 加=为了区分每一行内容
    while (StringUtils.isNotEmpty(
     line = bufferedReader.readLine())) {
         stringBuffer.append(line+"======");
            }
    //把内容写入到 v里面
            this.v.set(stringBuffer.toString());
     //  this.isNotRead=false代表内容已经读完
            this.isNotRead=false;
            return true;
        }
        return false;
    }

    //获取下一个Key
    @Override
    public Text getCurrentKey() throws IOException, InterruptedException {
      //this.key  获取下一个Key
        return this.key;
    }

    //获取下一个Value
    @Override
    public Text getCurrentValue() throws IOException, InterruptedException {
        //this.v 获取下一个Value
        return this.v;
    }

    //显示程序进程
    @Override
    public float getProgress() throws IOException, InterruptedException {
        return isNotRead ? 0 : 1;
    }

    //关闭程序
    @Override
    public void close() throws IOException {

    }
}

3.smallFileDriver 类

Driver 程序
设置一个变量接收文件,输入输出路径。
获取配置文件。
根据配置文件获取job实例。
关联驱动了。
设置输入类型。
设置文件,最终输出格式。
设置K和value最终输出类型。
设置文件,输入输出路径。
提交。

在这里插入代码片
```package com.jinghang.class30.smallFile;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;

import java.io.IOException;

public class smallFileDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//设置一个变量接收文件输入输出路径
    args = new String[]{"E:\\data\\input", "E:\\data\\output\\small"};

    //获取配置文件
    Configuration conf = new Configuration();

    //1.获取job实列
    Job job = Job.getInstance(conf);

    //2.关联驱动类
    job.setJarByClass(smallFileDriver.class);

    //3.设置输入类型
    job.setInputFormatClass(smallFileInputfromat.class);

    //4.设置文件最终输出格式
    job.setOutputFormatClass(SequenceFileOutputFormat.class);

    //5.设置key和value最终输出类型
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);

    //6。设置文件输入输出路径
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    //7.提交
    boolean b = job.waitForCompletion(true);
    //安全退出,0 或者 1
    System.out.println(b ? 0 : 1);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值