使用JAVA api读取HDFS文件乱码踩坑

想写一个读取HFDS上的部分文件数据做预览的接口,根据网上的博客实现后,发现有时读取信息会出现乱码,例如读取一个csv时,字符串之间被逗号分割

  • 英文字符串aaa,能正常显示

  • 中文字符串“你好”,能正常显示

  • 中英混合字符串如“aaa你好”,出现乱码

查阅了众多博客,解决方案大概都是:使用xxx字符集解码。抱着不信的想法,我依次尝试,果然没用。

解决思路

因为HDFS支持6种字符集编码,每个本地文件编码方式又是极可能不一样的,我们上传本地文件的时候其实就是把文件编码成字节流上传到文件系统存储。那么在GET文件数据时,面对不同文件、不同字符集编码的字节流,肯定不是一种固定字符集解码就能正确解码的吧。

那么解决方案其实有两种

  • 固定HDFS的编解码字符集。比如我选用UTF-8,那么在上传文件时统一编码,即把不同文件的字节流都转化为UTF-8编码再进行存储。这样的话在获取文件数据的时候,采用UTF-8字符集解码就没什么问题了。但这样做的话仍然会在转码部分存在诸多问题,且不好实现。

  • 动态解码。根据文件的编码字符集选用对应的字符集对解码,这样的话并不会对文件的原生字符流进行改动,基本不会乱码。

我选用动态解码的思路后,其难点在于如何判断使用哪种字符集解码。

好在看到了一篇博客

https://blog.csdn.net/smallnetvisitor/article/details/84682867

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 API读取HDFS的文件数据出现乱码的解决方案的更多相关文章

  1. Java API 读取HDFS的单文件

    HDFS上的单文件: -bash-3.2$ hadoop fs -ls /user/pms/ouyangyewei/data/input/combineorder/repeat_rec_categor ...

  2. java Api 读取HDFS文件内容

    package dao; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import java ...

  3. Spark:java api读取hdfs目录下多个文件

    需求: 由于一个大文件,在spark中加载性能比较差.于是把一个大文件拆分为多个小文件后上传到hdfs,然而在spark2.2下如何加载某个目录下多个文件呢? public class SparkJo ...

  4. 用java api读取HDFS文件

    import java.io.IOException; import java.io.InputStream; import java.security.PrivilegedExceptionActi ...

  5. JAVA API 实现hdfs文件操作

    java api 实现hdfs 文件操作会出现错误提示: Permission denied: user=hp, access=WRITE, inode="/":hdfs:supe ...

  6. 分享非常有用的Java程序(关键代码)(八)---Java InputStream读取网络响应Response数据的方法!(重要)

    原文:分享非常有用的Java程序(关键代码)(八)---Java InputStream读取网络响应Response数据的方法!(重要) Java InputStream读取数据问题 ======== ...

  7. 使用Java API操作HDFS文件系统

    使用Junit封装HFDS import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import org ...

  8. 使用Java Api 操作HDFS

    如题 我就是一个标题党  就是使用JavaApi操作HDFS,使用的是MAVEN,操作的环境是Linux 首先要配置好Maven环境,我使用的是已经有的仓库,如果你下载的jar包 速度慢,可以改变Ma ...

  9. C#选择多个文件并读取多个文件数据

    原文:C#选择多个文件并读取多个文件数据 版权声明:本文为博主原创文章,转载请附上链接地址. https://blog.csdn.net/ld15102891672/article/details/8 ...

随机推荐

  1. SpringBoot 完整学习笔记免费分享

    从0到进阶,完全系统性的学习笔记 每次我都会反复拿来观看,因为我们总会有遗漏忘记的地方,但是笔记不会. 希望大家能好好利用它,以下是笔记截图! 以上只是其中的一项部分,这份笔记可以说含金量超高,绝对会 ...

  2. Linux操作系统(第二版)(RHEL 8/CentOS 8)——勘误表

    Linux操作系统(第二版)(RHEL 8/CentOS 8)--勘误表 http://www.tup.tsinghua.edu.cn/booksCenter/book_08172501.html 本 ...

  3. CS61A Homework: Church Numerals

    Church Numerals Nagging 南大的 SICP 实际上是 Berkeley CS61A 的 clone ,所以我有幸做到了这个 Homework02. 此外要感谢选课系统,让我一个工 ...

  4. 【C/C++编程入门学习】C语言结构体硬核玩法分享,一切皆是数据!

    前言 对于结构体的应用太多了,今天这篇文章我主要为大家总结平时关于结构体的一些独特硬核小技巧,对于结构体更多优秀的编程表现,如果你对结构体的基础知识还不具备的话得回头看一下专栏教程或者自己找本书籍学习 ...

  5. gin+gorm 用户服务

    package main import ( "fmt" "github.com/gin-gonic/gin" "github.com/jinzhu/g ...

  6. .Net Core单元测试规范

    .Net Core单元测试规范 一. 前言 为了有效提升代码质量,保证DevOps的顺利进行.将全面开始采用单元测试进行覆盖,届时单元测试将完全纳入 到完整的持续构建生命周期中做为第一道质量把控的门槛 ...

  7. Eclipse JSP +Tomcat 环境搭建 错误记录

    环境搭建请参考原文:https://www.cnblogs.com/james-lee/p/5964238.html 错误1:运行时,弹出如下错误:(如果没有此错误,请忽略) 原因是,我们之前点击了T ...

  8. 分布式事务说的的2PC、3PC、TCC是啥

    目录 2PC(Two Phase Commit) 3PC(Three Phase Commit) TCC(Try-Confirm-Cancel) 2PC(Two Phase Commit) 顾名思义, ...

  9. Linux 生产主流版本

    CentOS 8 下载 https://mirrors.aliyun.com/centos/8.1.1911/isos/x86_64/CentOS-8.1.1911-x86_64-dvd1.iso L ...

  10. fish_redux使用详解---看完就会用!

    说句心里话,这篇文章,来来回回修改了很多次,如果认真看完这篇文章,还不会写fish_redux,请在评论里喷我. 前言 来学学难搞的fish_redux框架吧,这个框架,官方的文档真是一言难尽,比fl ...