亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

利用JAVA讀取HDFS文件數據時出現亂碼如何解決

發布時間:2020-11-17 14:42:22 來源:億速云 閱讀:273 作者:Leah 欄目:開發技術

利用JAVA讀取HDFS文件數據時出現亂碼如何解決?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

使用JAVA api讀取HDFS文件亂碼踩坑

想寫一個讀取HFDS上的部分文件數據做預覽的接口,根據網上的博客實現后,發現有時讀取信息會出現亂碼,例如讀取一個csv時,字符串之間被逗號分割

  • 英文字符串aaa,能正常顯示
  • 中文字符串“你好”,能正常顯示
  • 中英混合字符串如“aaa你好”,出現亂碼

查閱了眾多博客,解決方案大概都是:使用xxx字符集解碼。抱著不信的想法,我依次嘗試,果然沒用。

解決思路

因為HDFS支持6種字符集編碼,每個本地文件編碼方式又是極可能不一樣的,我們上傳本地文件的時候其實就是把文件編碼成字節流上傳到文件系統存儲。那么在GET文件數據時,面對不同文件、不同字符集編碼的字節流,肯定不是一種固定字符集解碼就能正確解碼的吧。

那么解決方案其實有兩種

  • 固定HDFS的編解碼字符集。比如我選用UTF-8,那么在上傳文件時統一編碼,即把不同文件的字節流都轉化為UTF-8編碼再進行存儲。這樣的話在獲取文件數據的時候,采用UTF-8字符集解碼就沒什么問題了。但這樣做的話仍然會在轉碼部分存在諸多問題,且不好實現。
  • 動態解碼。根據文件的編碼字符集選用對應的字符集對解碼,這樣的話并不會對文件的原生字符流進行改動,基本不會亂碼。

我選用動態解碼的思路后,其難點在于如何判斷使用哪種字符集解碼。參考下面的內容,獲得了解決方案

java檢測文本(字節流)的編碼方式

需求:

某文件或者某字節流要檢測他的編碼格式。

實現:

基于jchardet

<dependency>
	<groupId>net.sourceforge.jchardet</groupId>
	<artifactId>jchardet</artifactId>
	<version>1.0</version>
</dependency>

代碼如下:

public class DetectorUtils {
	private DetectorUtils() {
	}
 
	static class ChineseCharsetDetectionObserver implements
			nsICharsetDetectionObserver {
		private boolean found = false;
		private String result;
 
		public void Notify(String charset) {
			found = true;
			result = charset;
		}
 
		public ChineseCharsetDetectionObserver(boolean found, String result) {
			super();
			this.found = found;
			this.result = result;
		}
 
		public boolean isFound() {
			return found;
		}
 
		public String getResult() {
			return result;
		}
 
	}
 
	public static String[] detectChineseCharset(InputStream in)
			throws Exception {
		String[] prob=null;
		BufferedInputStream imp = null;
		try {
			boolean found = false;
			String result = Charsets.UTF_8.toString();
			int lang = nsPSMDetector.CHINESE;
			nsDetector det = new nsDetector(lang);
			ChineseCharsetDetectionObserver detectionObserver = new ChineseCharsetDetectionObserver(
					found, result);
			det.Init(detectionObserver);
			imp = new BufferedInputStream(in);
			byte[] buf = new byte[1024];
			int len;
			boolean isAscii = true;
			while ((len = imp.read(buf, 0, buf.length)) != -1) {
				if (isAscii)
					isAscii = det.isAscii(buf, len);
				if (!isAscii) {
					if (det.DoIt(buf, len, false))
						break;
				}
			}
 
			det.DataEnd();
			boolean isFound = detectionObserver.isFound();
			if (isAscii) {
				isFound = true;
				prob = new String[] { "ASCII" };
			} else if (isFound) {
				prob = new String[] { detectionObserver.getResult() };
			} else {
				prob = det.getProbableCharsets();
			}
			return prob;
		} finally {
			IOUtils.closeQuietly(imp);
			IOUtils.closeQuietly(in);
		}
	}
}

測試:

		String file = "C:/3737001.xml";
		String[] probableSet = DetectorUtils.detectChineseCharset(new FileInputStream(file));
		for (String charset : probableSet) {
			System.out.println(charset);
		}

Google提供了檢測字節流編碼方式的包。那么方案就很明了了,先讀一些文件字節流,用工具檢測編碼方式,再對應進行解碼即可。

具體解決代碼

pom

<dependency>
	<groupId>net.sourceforge.jchardet</groupId>
	<artifactId>jchardet</artifactId>
	<version>1.0</version>
</dependency>

從HDFS讀取部分文件做預覽的邏輯

 // 獲取文件的部分數據做預覽
 public List<String> getFileDataWithLimitLines(String filePath, Integer limit) {
  FSDataInputStream fileStream = openFile(filePath);
  return readFileWithLimit(fileStream, limit);
 }

 // 獲取文件的數據流
 private FSDataInputStream openFile(String filePath) {
  FSDataInputStream fileStream = null;
  try {
   fileStream = fs.open(new Path(getHdfsPath(filePath)));
  } catch (IOException e) {
   logger.error("fail to open file:{}", filePath, e);
  }
  return fileStream;
 }
 
 // 讀取最多limit行文件數據
 private List<String> readFileWithLimit(FSDataInputStream fileStream, Integer limit) {
  byte[] bytes = readByteStream(fileStream);
  String data = decodeByteStream(bytes);
  if (data == null) {
   return null;
  }

  List<String> rows = Arrays.asList(data.split("\\r\\n"));
  return rows.stream().filter(StringUtils::isNotEmpty)
    .limit(limit)
    .collect(Collectors.toList());
 }

 // 從文件數據流中讀取字節流
 private byte[] readByteStream(FSDataInputStream fileStream) {
  byte[] bytes = new byte[1024*30];
  int len;
  ByteArrayOutputStream stream = new ByteArrayOutputStream();
  try {
   while ((len = fileStream.read(bytes)) != -1) {
    stream.write(bytes, 0, len);
   }
  } catch (IOException e) {
   logger.error("read file bytes stream failed.", e);
   return null;
  }
  return stream.toByteArray();
 }

 // 解碼字節流
 private String decodeByteStream(byte[] bytes) {
  if (bytes == null) {
   return null;
  }

  String encoding = guessEncoding(bytes);
  String data = null;
  try {
   data = new String(bytes, encoding);
  } catch (Exception e) {
   logger.error("decode byte stream failed.", e);
  }
  return data;
 }

 // 根據Google的工具判別編碼
 private String guessEncoding(byte[] bytes) {
  UniversalDetector detector = new UniversalDetector(null);
  detector.handleData(bytes, 0, bytes.length);
  detector.dataEnd();
  String encoding = detector.getDetectedCharset();
  detector.reset();

  if (StringUtils.isEmpty(encoding)) {
   encoding = "UTF-8";
  }
  return encoding;
 }

關于利用JAVA讀取HDFS文件數據時出現亂碼如何解決問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

廊坊市| 八宿县| 二连浩特市| 卢龙县| 石城县| 新巴尔虎左旗| 通化县| 小金县| 苏尼特右旗| 东城区| 德清县| 工布江达县| 吉安县| 祁阳县| 石河子市| 武川县| 安吉县| 思茅市| 伊吾县| 乐东| 都江堰市| 梁平县| 通许县| 福安市| 三明市| 通辽市| 和政县| 泸定县| 婺源县| 抚宁县| 江津市| 徐水县| 威信县| 五大连池市| 哈尔滨市| 乐清市| 自治县| 尼玛县| 龙江县| 五莲县| 雅安市|