Mapreduce清洗出来的数据,遇到中文乱码的问题
Map端读取文本数据,在map方法里对数据进行拆分解析,按行读取到的数据为Text类型,hadoop的Text类的内部编码格式是写死的UTF-8(看源码),如果文件编码格式是其他类型(如GBK),在map方法读取数据后要直接进行编码转换,不然得到的数据就会出现乱码问题。
此时我们将原本的:String line=value.toString();
改为:String line=new String(value.getBytes(),0,value.getLength(),“GBK”);
就可以解决了。
public class Map extends Mapper<LongWritable, Text, Text, Text>{
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//String line=value.toString()
String line=new String(value.getBytes(),0,value.getLength(),"GBK");
context.write(new Text(s),new Text(s));
}
}
直接使用String line=value.toString();会出现乱码,这是由于Text这个Writable类型造成的。像初学者,很容易认为和LongWritable类型是long的Writable封装一样,Text类型是String的Writable封装,其实这两者是有区别的,Text是文本按照UTF-8格式编码的Writable,而Java中的String是Unicode字符编码。所以直接使用value.toString()方法,会默认其中的字符都是按照UTF-8进行编码过的,原本GBK编码的数据使用Text读入后直接使用该方法就会变成乱码。正确的方法是将输入的Text类型的value转换为字节数组(value.getBytes())使用String的构造器String(byte[] bytes, int offset, int length, Charset charset)通过使用指定的charset解码指定的byte子数组,构造一个新的String。
同理,输出的时候也是用Text封装的字符串,所以输出文件中如果按照默认格式输出,编码方式也是UTF-8;
如果需要map/reduce输出其它编码格式的数据,需要自己实现OutputFormat,在其中指定编码方式,不能使用默认的TextOutputFormat