单位用的是Linux系统的字符编码是gb2312,所以生成的文件都是按照默认编码生成的。给我的文件也都是gb2312的,在hadoop中运行mapreduce出现乱码,在网上查资料说是因为hadoop的文件系统默认用的是utf-8,那么只有两条路可以选,要么改文件的编码格式,要么改在Mapreduce程序中想办法转一下。很显然改文件的编码格式是不现实的,因为客户那边用C++生成的文件千千万万,而且原来的老程序还在不断的生成,要他们改程序涉及到的工作量太大了。所以这能我这边想办法了。
因为Mapreduce涉及到读和写两个操作。首先在Map中读的时候需要使用gb2312的方式去读取文件,然后Reduce中写文件的时候需要以gb2312的方式去写。想想其实如果在Reduce中写的时候不用gb2312的方式去写,那么就用默认的UTF-8去写,原理上只要把这个文件下载下来,拷贝到一个能够识别gb2312文件格式的系统上去,应该看到的不是乱码,这个没有试过。由于操作系统字符编码是gb2312,所以为了生成的文件不是乱码,reduce中写的是时候还是用gb2312的方式去写吧。下面说说具体操作步骤:
1、在Map中以gb2312的方式去读取文件,只需要两行代码转换一下就可以。
String line = value.toString(); line = new String(line .getBytes(), 0, line .length, "gb2312");
2、在reduce中写的时候用gb2312去写,这个时候需要重写一个类,代替原来的TextOutputFormat类。新的类代码如下:
public class GbkOutputFormat<K, V> extends FileOutputFormat<K, V> { protected static class LineRecordWriter<K, V> implements RecordWriter<K, V> { //写成gbk即可 private static final String gbk = “gb2312”; private static final byte[] newline; static { try { newline = “\n”.getBytes(gbk); } catch (UnsupportedEncodingException uee) { throw new IllegalArgumentException(“can’t find ” + gbk + ” encoding”); } } … 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”); } } … 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(gbk)); } } … } 然后在mapreduce代码中加入conf1.setOutputFormat(GbkOutputFormat.class) 即可以gbk格式输出中文。
本文参考:http://blog.csdn.net/zklth/article/details/11829563
时间: 2024-11-05 06:27:29