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的文件数据出现乱码的解决方案的详细内容,更多关于JAVA读取HDFS的文件乱码的资料请关注猪先飞其它相关文章!
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
- 最近做了个扫描二维码得到vcard的项目,遇到一个问题,有一部分生成完的二维码,用android系统手机扫描后得到的vcard中的中文姓名是乱码,经过比对发现,这部分vcard中ORG这个...2016-11-25
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 今天在写一个vbs的时候,发现中文乱码,后来写好代码正常运行的代码压缩一下给了同事,发现报无效字符,经过验证后发现原来是编码的问题导致,这里就为大家分享一下...2020-06-30
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
关于Mysql中文乱码问题该如何解决(乱码问题完美解决方案)
最近两天做项目总是被乱码问题困扰着,这不刚把mysql中文乱码问题解决了,下面小编把我的解决方案分享给大家,供大家参考,也方便以后自己查阅。首先:用show variables like “%colla%”;show varables like “%char%”;这两条...2015-11-24- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了C#读取中文文件出现乱码的解决方法,涉及C#中文编码的操作技巧,非常具有实用价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 在 php 中使用 json_encode() 内置函数(php > 5.2)可以使用得 php 中数据可以与其它语言很好的传递并且使用它。这个函数的功能是将数值转换成json数据存储格式。<?php$arr = array ( 'Name'=>'希亚', 'Age'...2015-11-08
- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29