spark 中文編碼處理
阿新 • • 發佈:2019-01-26
日誌的格式是GBK編碼的,而hadoop上的編碼是用UTF-8寫死的,導致最終輸出亂碼。
研究了下Java的編碼問題。
網上其實對spark輸入檔案是GBK編碼有現成的解決方案,具體程式碼如下
import org.apache.hadoop.io.LongWritable import org.apache.hadoop.io.Text import org.apache.hadoop.mapred.TextInputFormat rdd = ctx.hadoopFile(file_list, classOf[TextInputFormat], classOf[LongWritable], classOf[Text]).map( pair=> new String(pair._2.getBytes, 0, pair._2.getLength, "GBK"))
這種想法的來源是基於
public static Text transformTextToUTF8(Text text, String encoding) { String value = null; try { value = new String(text.getBytes(), 0, text.getLength(), encoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); }return new Text(value); }
但這種方法還有一個問題,
大家都知道gbk是2~3個位元組編碼的。如果日誌中按照直接截斷,導致按照gbk讀取檔案的時候,將後面的分隔符\t一併讀取了 ,導致按照\t split的時候,欄位的個數不對(或者說順序錯位了)。
這個時候,需要找到一種單位元組的解析方案,即 ISO-8859-1編碼。程式碼如下
rdd = ctx.hadoopFile(file_list, classOf[TextInputFormat], classOf[LongWritable], classOf[Text]).map( pair=> new String(pair._2.getBytes, 0, pair._2.getLength, "ISO-8859-1"))
但這又帶來了一個問題,即輸出的結果(按照UTF-8儲存)是亂碼,不可用。
如果我們換一種思路來考慮這個問題,Java或scala中如何將一個gbk檔案轉換為UTF8?網上有很多的現成的程式碼,具體到我們的場景,以行為單位處理的話,示例程式碼如下
public class Encoding { private static String kISOEncoding = "ISO-8859-1"; private static String kGBKEncoding = "GBK"; private static String kUTF8Encoding = "UTF-8"; public static void main(String[] args) throws UnsupportedEncodingException { try { File out_file = new File(args[1]); Writer out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(out_file), kUTF8Encoding)); List<String> lines = Files.readAllLines(Paths.get(args[0]), Charset.forName(kGBKEncoding)); for (String line : lines) { out.append(line).append("\n"); } out.flush(); out.close(); } catch (IOException e) { System.out.println(e); } } }
如上的程式碼給了我們一個啟示,即在寫入檔案的時候,系統自動進行了編碼的轉換,我們沒必要對行進行單獨的直接轉換處理。
通過查詢資料,Java中字元編碼是內部編碼,即位元組流按照編碼轉化為String。
所謂結合以上兩點認識,我們模擬在spark上以ISO-8859-1
開啟檔案和以UTF-8寫入檔案的過程,發現只需要將其強制轉換為GBK的string即可,最終得到的檔案以UTF-8開啟不是亂碼,具體程式碼如下。
public class Encoding { private static String kISOEncoding = "ISO-8859-1"; private static String kGBKEncoding = "GBK"; private static String kUTF8Encoding = "UTF-8"; public static void main(String[] args) throws UnsupportedEncodingException { try { File out_file = new File(args[1]); Writer out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(out_file), kUTF8Encoding)); List<String> lines = Files.readAllLines(Paths.get(args[0]), Charset.forName(kISOEncoding)); for (String line : lines) { String gbk_str = new String(line.getBytes(kISOEncoding), kGBKEncoding); out.append(gbk_str).append("\n"); } out.flush(); out.close(); } catch (IOException e) { System.out.println(e); } } }
完美的解決了。。。花費了一個工作日解決才解決的問題,對Java還是不夠熟練啊。
總結出來,希望對大家有用。
總結
1. 要舉一反三
2. 學會google,最近我就指望著它活著了。