字符编码转换

Java
Scala
Spark

scala中怎么把字符的编码方式从gbk转换成utf8?

如题,初学者,遇到一个文件转换问题,要把文件的字符编码从gbk变成utf8T_TT_T,时间紧,任务重
关注者
3
被浏览
4,077
2 个回答
默认排序 ​
3 人赞同了该回答
1. 假设你使用了Apache的Commons-io包 Commons IO - Commons IO Overview,可以使用如下代码:
import java.io.File
import org.apache.commons.io.FileUtils

val file = new File(filename)
content = FileUtils.readFileToString(file, "gbk")
FileUtils.write(file, content, "UTF-8")


2. 如果你用的是JAVA7:
import java.nio.file.{Paths, Files}

val content = io.Source.fromFile(filename, "gbk").mkString
Files.write(Paths.get(filename), content.getBytes("UTF8"))
3 ​1 条评论
​分享
​收藏 ​感谢
一年多以前问的问题,那时候需要使用spark读取GBK文件来处理数据,最后是先对文件转码,然后再用spark来处理的,那时候啥也不懂,只知道hadoop只能读取utf8的文件,具体是因为什么也不知道,最近又想到这个问题,看看源码来详细说明一下,还有解决的办法
其实无论是spark,还是hadoop在使用默认方法读取文本文件的时候都是使用了TextInputFormat来解析的文件,一般的在spark中使用textFile方法来从一般的文件创建RDD
def textFile(
     path: String,
     minPartitions: Int = defaultMinPartitions): RDD[String] = withScope {
     assertNotStopped()
     hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text],
     minPartitions).map(pair => pair._2.toString).setName(path)
 }
而TextInputFormat会负责做两件事,一是根据输入的文件路径来对文件分片,对于每个分片,hadoop都会启动一个map任务来处理,spark中则是一个task,这个功能是由TextInputFormat的父类来实现的;二是读取分片中的数据,并不断的生成KV键值对RecordReader交给map方法去处理。而在TextInputFormat中有一个设置字符集的地方 Charsets.UTF_8,然而这里并不是我们想要的,而是指定“行“分隔符,具体用处下面在介绍,
public class TextInputFormat extends FileInputFormat<LongWritable, Text> {

  @Override
  public RecordReader<LongWritable, Text> 
    createRecordReader(InputSplit split,
                       TaskAttemptContext context) {
    String delimiter = context.getConfiguration().get(
        "textinputformat.record.delimiter");
    byte[] recordDelimiterBytes = null;
    if (null != delimiter)
      recordDelimiterBytes = delimiter.getBytes(Charsets.UTF_8);
    return new LineRecordReader(recordDelimiterBytes);
  }

  @Override
  protected boolean isSplitable(JobContext context, Path file) {
    final CompressionCodec codec =
      new CompressionCodecFactory(context.getConfiguration()).getCodec(file);
    if (null == codec) {
      return true;
    }
    return codec instanceof SplittableCompressionCodec;
  }

}

LineRecordReader的nextKeyValue()方法中value从输入流中获取,最终发现value获取的是字节码数据,读取过程并没有对数据做编码的操作,所以在map端获得的value的值依旧是字节码数据,猜想是不是可以在map方法中对获得的value字节码按照GBK编码读取。尝试了一下,没有出现乱码问题,所以

解决方法:
spark读取GBK编码文件
new String(p._2.getBytes, 0, p._2.getLength, "GBK")

使用GBK编码转String

 def main(args: Array[String]): Unit = {
    val conf = new SparkConf()
      .setAppName(" GBK TO UTF8")
      .setMaster("local")
 
    val sc = new SparkContext(conf)
 
    val rdd = sc.hadoopFile("F:\\data\\score.txt", classOf[TextInputFormat], classOf[LongWritable], classOf[Text], 1)
      .map(p => new String(p._2.getBytes, 0, p._2.getLength, "GBK"))
      .flatMap(s => s.split(","))
      .map(x => (x, 1))
      .reduceByKey(_ + _)
      .collect
      .foreach(println)
  }

hadoop读取GBK编码文件
不要使用常用的value.toString()方法,那样就会出现乱码问题,
public void map(LongWritable key, Text value, Context context) {
        try {

            String line;
            line = new String(value.getBytes(), 0, value.getLength(), "GBK");//使用GBK解析字节码 ,转成String
            logger.info("gbkstr " + line);
            
            //不要使用toStirng方法来获取字符串
            //line = value.toString();    
            //logger.info("str " + line);
            
              String[] item = line.split(",");
            for (String str : item) {
                outkey = new Text(str);
                context.write(outkey, outvalue);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值