Hadoop字符集转换问题

前言

写在前面,如果输入的文件是UTF-8,不需要进行任何转换处理。
如果是其他类型的字符,则需要进行处理,否则Hadoop显示和处理会出错,而且写入输出文件是乱码。

思路

读取文件的时候如果文件的格式是GBK那么,用Hadoop默认的读取会出现乱码,同时也会影响操作。
因此在读取的时候需要按照GBK的格式进行读取。
当处理完成后,需要将输出文件也设置成GBK的格式进行输出。
在map函数中执行读取的操作进行编码转换。

 public static class Map extends Mapper<LongWritable, Text, Text, IntWritable>
{
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException
    {       
        String line = new String(value.getBytes(),0,value.getLength(),"GBK");
        ......................
    }
    ...............
}

输出的时候需要将输出文件的内容设置成GBK,这个时候需要重写输出处理类。
以前用的是这个:

job.setOutputFormatClass(TextOutputFormat.class);

代码实现

现在实现一个这个,基本上就是复制粘贴了TextOutputFormat这个类,里面做了很少的处理。

TextOutputFormat源码

public class TextOutputFormat<K, V> extends FileOutputFormat<K, V> {
  public static String SEPERATOR = "mapreduce.output.textoutputformat.separator";
  protected static 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");
    }

    /**
     * Write the object to the byte stream, handling Text as a special
     * case.
     * @param o the object to print
     * @throws IOException if the write throws, we pass it on
     */
    private void writeObject(Object o) throws IOException {
      if (o instanceof Text) {
        Text to = (Text) o;
        out.write(to.getBytes(), 0, to.getLength());
      } 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;
      if (nullKey && nullValue) {
        return;
      }
      if (!nullKey) {
        writeObject(key);
      }
      if (!(nullKey || nullValue)) {
        out.write(keyValueSeparator);
      }
      if (!nullValue) {
        writeObject(value);
      }
      out.write(newline);
    }

    public synchronized 
    void close(TaskAttemptContext context) throws IOException {
      out.close();
    }
  }

  public RecordWriter<K, V> getRecordWriter(TaskAttemptContext job) throws IOException, InterruptedException {
    Configuration conf = job.getConfiguration();
    boolean isCompressed = getCompressOutput(job);
    String keyValueSeparator= conf.get(SEPERATOR, "\t");
    CompressionCodec codec = null;
    String extension = "";
    if (isCompressed) {
      Class<? extends CompressionCodec> codecClass = 
        getOutputCompressorClass(job, GzipCodec.class);
      codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
      extension = codec.getDefaultExtension();
    }
    Path file = getDefaultWorkFile(job, extension);
    FileSystem fs = file.getFileSystem(conf);
    if (!isCompressed) {
      FSDataOutputStream fileOut = fs.create(file, false);
      return new LineRecordWriter<K, V>(fileOut, keyValueSeparator);
    } else {
      FSDataOutputStream fileOut = fs.create(file, false);
      return new LineRecordWriter<K, V>(new DataOutputStream
                                        (codec.createOutputStream(fileOut)),
                                        keyValueSeparator);
    }
  }
}

GBKTextOutputFormat的源码

public class GBKTextOutputFormat<K, V> extends FileOutputFormat<K, V>
{

    public static String SEPERATOR = "mapreduce.output.textoutputformat.separator";

    protected static class LineRecordWriter<K, V> extends RecordWriter<K, V>
    {
        private static final String gbk = "gbk";//******
        private static final byte[] newline;
        static
        {
            try
            {
                newline = "\n".getBytes(gbk);
            }
            catch (UnsupportedEncodingException uee)
            {
                throw new IllegalArgumentException("can't find " + gbk + " encoding");
            }
        }

        protected DataOutputStream out;
        private final byte[] keyValueSeparator;

        public LineRecordWriter(DataOutputStream out, String keyValueSeparator)
        {
            this.out = out;
            try
            {
                this.keyValueSeparator = keyValueSeparator.getBytes(gbk);
            }
            catch (UnsupportedEncodingException uee)
            {
                throw new IllegalArgumentException("can't find " + gbk + " encoding");
            }
        }

        public LineRecordWriter(DataOutputStream out)
        {
            this(out, "\t");
        }

        /**
         * Write the object to the byte stream, handling Text as a special case.
         * 
         * @param o
         *            the object to print
         * @throws IOException
         *             if the write throws, we pass it on
         */
        private void writeObject(Object o) throws IOException
        {
            //******
            out.write(o.toString().getBytes(gbk));
            //******
        }

        public synchronized void write(K key, V value) throws IOException
        {

            boolean nullKey = key == null || key instanceof NullWritable;
            boolean nullValue = value == null || value instanceof NullWritable;
            if (nullKey && nullValue)
            {
                return;
            }
            if (!nullKey)
            {
                writeObject(key);
            }
            if (!(nullKey || nullValue))
            {
                out.write(keyValueSeparator);
            }
            if (!nullValue)
            {
                writeObject(value);
            }
            out.write(newline);
        }

        public synchronized void close(TaskAttemptContext context) throws IOException
        {
            out.close();
        }
    }

    public RecordWriter<K, V> getRecordWriter(TaskAttemptContext job) throws IOException, InterruptedException
    {
        Configuration conf = job.getConfiguration();
        boolean isCompressed = getCompressOutput(job);
        String keyValueSeparator = conf.get(SEPERATOR, "\t");
        CompressionCodec codec = null;
        String extension = "";
        if (isCompressed)
        {
            Class<? extends CompressionCodec> codecClass = getOutputCompressorClass(job, GzipCodec.class);
            codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);
            extension = codec.getDefaultExtension();
        }
        Path file = getDefaultWorkFile(job, extension);
        FileSystem fs = file.getFileSystem(conf);
        if (!isCompressed)
        {
            FSDataOutputStream fileOut = fs.create(file, false);
            return new LineRecordWriter<K, V>(fileOut, keyValueSeparator);
        }
        else
        {
            FSDataOutputStream fileOut = fs.create(file, false);
            return new LineRecordWriter<K, V>(new DataOutputStream(codec.createOutputStream(fileOut)),
                    keyValueSeparator);
        }
    }

}

使用的时候

job.setOutputFormatClass(GBKTextOutputFormat.class);

看输出结果,正确。

原因就是hadoop为了通用性,所有的处理都是UTF-8,这个只是特殊处理,建议输入文件采用UTF-8的格式。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,作为AI语言模型,我无法直接生成文本文件数据集和编写 MapReduce 程序。但是,我可以帮你解释一下题目中提到的一些概念和要求,希望能对你有所帮助。 题目中要求生成文本文件数据集并按照要求编写 WordCount 程序,这是一个典型的 MapReduce 任务。MapReduce 是一种分布式计算框架,可以处理大规模数据集。在这个任务中,需要编写 Map 和 Reduce 函数,Map 函数将文本文件中的单词转换为键值对,Reduce 函数将相同单词的键值对进行合并,并计算出每个单词的出现次数。 在题目要求的 WordCount 程序中,需要去除所有非 a-z 与 A-Z 的字符,并转换为小写。这可以通过在 Map 函数中进行字符串处理来实现。具体来说,在 Map 函数中,可以使用正则表达式去除非 a-z 与 A-Z 的字符,并将字符串转换为小写。例如,可以使用 Java 中的 String.replaceAll() 方法来去除非 a-z 与 A-Z 的字符。 在 MapReduce 最终输出结果中,要求满足词频按照降序排列、同一频数下按照字典序降序排列。这可以通过在 Reduce 函数中进行排序来实现。具体来说,在 Reduce 函数中,可以将键值对按照值进行排序,并将结果输出到文件中。 最后,需要注意的是,题目中要求输出结果存放于 Hadoop 文件系统的 /学号-quest-1-output 目录下,其中学号需要替换为自己的学号。同时,任务命名也需要按照要求命名。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值