Hadoop 檔案輸入和檔案輸出

來源:互聯網
上載者:User

本文完成對hadoop輸入、輸出檔案方式的控制,完成的功能如下:

1、改寫map讀取資料的格式:預設的<檔案位移量,行內容>----------->變為<檔案名稱,檔案內容>

2、改寫輸出的格式,輸出檔案時每個輸入檔案對應一個輸出檔案,輸出檔案的名字跟輸入檔案名稱字相同。

直接上代碼:

coAuInputFormat

package an.hadoop.code.audit;/** * The function of this class is revise the input format  * the <key,value > ---> map * <path,content> of the map * */import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.Text;import org.apache.hadoop.io.compress.CompressionCodec;import org.apache.hadoop.io.compress.CompressionCodecFactory;import org.apache.hadoop.mapred.FileSplit;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.FileInputFormat;public class coAuInputFormat extends FileInputFormat<Text, Text>{private CompressionCodecFactory compressionCodecs = null;public void configure(Configuration conf) {compressionCodecs = new CompressionCodecFactory(conf);}/** * @brief isSplitable 不對檔案進行切分,必須對檔案整體進行處理 * * @param fs * @param file * * @return false */protected boolean isSplitable(FileSystem fs, Path file) {CompressionCodec codec = compressionCodecs.getCodec(file);return false;//以檔案為單位,每個單位作為一個split,即使單個檔案的大小超過了64M,也就是Hadoop一個塊得大小,也不進行分區}@Overridepublic RecordReader<Text, Text> createRecordReader(InputSplit split,TaskAttemptContext context) throws IOException,InterruptedException {// TODO Auto-generated method stubreturn new coAuRecordReader(context, split);}}

coAuRecordReader

package an.hadoop.code.audit;import java.io.IOException;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;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.Text;import org.apache.hadoop.io.compress.CompressionCodec;import org.apache.hadoop.io.compress.CompressionCodecFactory;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;public class coAuRecordReader extends RecordReader<Text, Text> {private static final Log LOG = LogFactory.getLog(coAuRecordReader.class.getName());private CompressionCodecFactory compressionCodecs = null;private long start;private long pos;private long end;private byte[] buffer;private String keyName;private FSDataInputStream fileIn;private Text key = null;    private Text value = null;public coAuRecordReader(TaskAttemptContext context, InputSplit genericSplit) throws IOException {// TODO Auto-generated constructor stubConfiguration job = context.getConfiguration();FileSplit split = (FileSplit) genericSplit;start = ((FileSplit) split).getStart(); //從中可以看出每個檔案是作為一個split的end = split.getLength() + start;final Path path = split.getPath();//keyName = path.toString();//key 的值是檔案路徑LOG.info("filename in hdfs is : " + keyName);//寫入記錄檔,去哪裡查看日誌呢?final FileSystem fs = path.getFileSystem(job);fileIn = fs.open(path);fileIn.seek(start);buffer = new byte[(int)(end - start)];this.pos = start;/*if(key == null){key = new Text();key.set(keyName);}if(value == null){value = new Text();value.set(utf8);}*/}//coAuRecordReader()@Overridepublic void initialize(InputSplit genericSplit, TaskAttemptContext context)throws IOException, InterruptedException {// TODO Auto-generated method stubFileSplit split = (FileSplit) genericSplit;    Configuration job = context.getConfiguration();    //this.maxLineLength = job.getInt("mapred.linerecordreader.maxlength",Integer.MAX_VALUE);    start = split.getStart();    end = start + split.getLength();    final Path file = split.getPath();    compressionCodecs = new CompressionCodecFactory(job);    final CompressionCodec codec = compressionCodecs.getCodec(file);    keyName = file.toString();//key 的值是檔案路徑LOG.info("filename in hdfs is : " + keyName);//寫入記錄檔,去哪裡查看日誌呢?final FileSystem fs = file.getFileSystem(job);fileIn = fs.open(file);fileIn.seek(start);buffer = new byte[(int)(end - start)];this.pos = start;}@Overridepublic boolean nextKeyValue() throws IOException, InterruptedException {// TODO Auto-generated method stub//這個是需要做的if(key == null){key = new Text();}key.set(keyName);if(value == null){value = new Text();}key.clear();key.set(keyName);// set the keyvalue.clear();//clear the valuewhile(pos < end){fileIn.readFully(pos,buffer);value.set(buffer);pos += buffer.length;LOG.info("end is : " + end  + " pos is : " + pos);return true;}return false;}@Overridepublic Text getCurrentKey() throws IOException, InterruptedException {// TODO Auto-generated method stubreturn key;}@Overridepublic Text getCurrentValue() throws IOException, InterruptedException {// TODO Auto-generated method stubreturn value;}@Overridepublic float getProgress() throws IOException, InterruptedException {// TODO Auto-generated method stubif (start == end) {return 0.0f;} else {return Math.min(1.0f, (pos - start) / (float)(end - start));}}@Overridepublic void close() throws IOException {// TODO Auto-generated method stubif (fileIn != null) {        fileIn.close();     }}}

coAuOutputFormat

package an.hadoop.code.audit;/** * the name of the output file name *  * */import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;public class coAuOutputFormat extends MultipleOutputFormat<Text, Text> {private final static String suffix = "_its4";@Overrideprotected String generateFileNameForKeyValue(Text key, Text value,Configuration conf) {// TODO Auto-generated method stubString path =  key.toString(); //檔案的路徑及名字String[] dir = path.split("/");int length = dir.length; String filename = dir[length -1];return filename + suffix;//輸出的檔案名稱,輸出的檔案名稱}}

MultipleOutputFormat

package an.hadoop.code.audit;/** * the mutiply  * */import java.io.DataOutputStream;import java.io.IOException;import java.util.HashMap;import java.util.Iterator;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FSDataOutputStream;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.Writable;import org.apache.hadoop.io.WritableComparable;import org.apache.hadoop.io.compress.CompressionCodec;import org.apache.hadoop.io.compress.GzipCodec;import org.apache.hadoop.mapreduce.OutputCommitter;import org.apache.hadoop.mapreduce.RecordWriter;import org.apache.hadoop.mapreduce.TaskAttemptContext;import org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import org.apache.hadoop.util.ReflectionUtils;public abstract class MultipleOutputFormat<K extends WritableComparable<?>, V extends Writable>extends FileOutputFormat<K, V> { //預設的是TextOutputFormatprivate MultiRecordWriter writer = null;public RecordWriter<K, V> getRecordWriter(TaskAttemptContext job) throws IOException,InterruptedException {if (writer == null) {writer = new MultiRecordWriter(job, getTaskOutputPath(job));//job ,output path}return writer;}private Path getTaskOutputPath(TaskAttemptContext conf) throws IOException {//獲得輸出路徑Path workPath = null;OutputCommitter committer = super.getOutputCommitter(conf);if (committer instanceof FileOutputCommitter) {//如果是workPath = ((FileOutputCommitter) committer).getWorkPath();//工作路徑} else {Path outputPath = super.getOutputPath(conf);//獲得conf路徑if (outputPath == null) {throw new IOException("Undefined job output-path");}workPath = outputPath;}return workPath; //}/**通過key, value, conf來確定輸出檔案名(含副檔名)*/protected abstract String generateFileNameForKeyValue(K key, V value, Configuration conf);//抽象方法,被之後的方法重寫了public class MultiRecordWriter extends RecordWriter<K, V> {/**RecordWriter的緩衝*/private HashMap<String, RecordWriter<K, V>> recordWriters = null;private TaskAttemptContext job = null;/**輸出目錄*/private Path workPath = null;public MultiRecordWriter(TaskAttemptContext job, Path workPath) {//建構函式super();this.job = job;this.workPath = workPath;recordWriters = new HashMap<String, RecordWriter<K, V>>();}@Overridepublic void close(TaskAttemptContext context) throws IOException, InterruptedException {//多個writer都要關掉Iterator<RecordWriter<K, V>> values = this.recordWriters.values().iterator();while (values.hasNext()) {values.next().close(context);}this.recordWriters.clear();}@Overridepublic void write(K key, V value) throws IOException, InterruptedException {//得到輸出檔案名String baseName = generateFileNameForKeyValue(key, value, job.getConfiguration());//產生輸出檔案名RecordWriter<K, V> rw = this.recordWriters.get(baseName);//??if (rw == null) {rw = getBaseRecordWriter(job, baseName);//this.recordWriters.put(baseName, rw);}rw.write(key, value);}// ${mapred.out.dir}/_temporary/_${taskid}/${nameWithExtension}private RecordWriter<K, V> getBaseRecordWriter(TaskAttemptContext job, String baseName)throws IOException, InterruptedException {Configuration conf = job.getConfiguration();boolean isCompressed = getCompressOutput(job);String keyValueSeparator = ",";RecordWriter<K, V> recordWriter = null;if (isCompressed) {Class<? extends CompressionCodec> codecClass = getOutputCompressorClass(job,GzipCodec.class);CompressionCodec codec = ReflectionUtils.newInstance(codecClass, conf);Path file = new Path(workPath, baseName + codec.getDefaultExtension());FSDataOutputStream fileOut = file.getFileSystem(conf).create(file, false);recordWriter = new LineRecordWriter<K, V>(new DataOutputStream(codec.createOutputStream(fileOut)), keyValueSeparator);} else {Path file = new Path(workPath, baseName);FSDataOutputStream fileOut = file.getFileSystem(conf).create(file, false);//file 是指的file name of the output filerecordWriter = new LineRecordWriter<K, V>(fileOut, keyValueSeparator);//這裡調用的LineRecordWriter}return recordWriter;}}}

LineRecordWriter

package an.hadoop.code.audit;/*RecordWriter的一個實現,用於把<Key, Value>轉化為一行文本。在Hadoop中,這個類作為TextOutputFormat的一個子類存在, * protected存取權限,因此普通程式無法訪問。這裡僅僅是把LineRecordWriter從TextOutputFormat抽取出來,作為一個獨立的公用*/import java.io.DataOutputStream;import java.io.IOException;import java.io.UnsupportedEncodingException;import org.apache.hadoop.io.NullWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.RecordWriter;import org.apache.hadoop.mapreduce.TaskAttemptContext;import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;/**摘自{@link TextOutputFormat}中的LineRecordWriter。 */public class LineRecordWriter<K, V> extends RecordWriter<K, V> {private static final String utf8 = "UTF-8";private static final byte[] newline;static {try {newline = "\n".getBytes(utf8);// 相當與分隔字元} catch (UnsupportedEncodingException uee) {throw new IllegalArgumentException("can't find " + utf8 + " encoding");}}protected DataOutputStream out;private final byte[] keyValueSeparator;public LineRecordWriter(DataOutputStream out, String keyValueSeparator) {this.out = out;try {this.keyValueSeparator = keyValueSeparator.getBytes(utf8);} catch (UnsupportedEncodingException uee) {throw new IllegalArgumentException("can't find " + utf8 + " encoding");}}public LineRecordWriter(DataOutputStream out) {this(out, "/t");//"/t"預設的分隔字元}private void writeObject(Object o) throws IOException {//被write函數調用if (o instanceof Text) {//Text to = (Text) o;out.write(to.getBytes(), 0, to.getLength());//將指定 byte 數組中從位移量 off 開始的 len 個位元組寫入基礎輸出資料流} else {out.write(o.toString().getBytes(utf8));}}public synchronized void write(K key, V value) throws IOException {//這個要修改成 只是寫成一個檔案的格式,boolean nullKey = key == null || key instanceof NullWritable;boolean nullValue = value == null || value instanceof NullWritable;//重點是要改寫Key,value,之類,value是一個文本,key是地址,這裡不寫入key了if (nullKey && nullValue) {return;}/*if (!nullKey) {//這個可以控制是否寫入key,seperate and valuewriteObject(key);}if (!(nullKey || nullValue)) {out.write(keyValueSeparator);}*/if (!nullValue) {writeObject(value);}out.write(newline);}public synchronized void close(TaskAttemptContext context) throws IOException {out.close();}}

CodeAudit

package an.hadoop.code.audit;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.NullWritable;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.util.GenericOptionsParser;public class CodeAudit {public static void main(String[] args) throws Exception {    Configuration conf = new Configuration();    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();    if (otherArgs.length != 2) {      System.err.println("Usage: code audit <in> <out>");      System.exit(2);    }    Job job = new Job(conf, "code audit");    job.setJarByClass(CodeAudit.class);    job.setMapperClass(coAuMapper.class);    job.setInputFormatClass(coAuInputFormat.class);    //job.setOutputKeyClass(NullWritable.class);    job.setOutputKeyClass(Text.class);    job.setOutputValueClass(Text.class);        job.setOutputFormatClass(coAuOutputFormat.class);    FileInputFormat.addInputPath(job, new Path(otherArgs[0]));    FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));    System.exit(job.waitForCompletion(true) ? 0 : 1);  }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.