11、HDFS编程案例
一、Windows环境配置
1、准备好hadoop的完全分布式按照,具体按照步骤这里不再赘述
此处我的版本为hadoop2.7.6版本,环境配置为Hadoop的完全分布式按照,各个节点具体安排如下
1)机器地址映射关系
192.168.8.240 hadoop01
192.168.8.241 hadoop02
192.168.8.242 hadoop03
2)机器节点安排
hadoop01 namenode datanode nodemanager hadoop02
secondarynamenode datanode nodemanager hadoop03
resourcemanager datanode nodemanager
HDFS:分布式文件
hadoop01为namenode,其他都为datanode(包括hadoop01自己)
YARN:分布式计算
hadoop03为resourcemanager管理节点,其他为计算节点nodemanager
3)说明
namenode最好单独出来,减轻元数据负载压力
secondarynamenode最好不要与namenode放置在同一台机器进行冷备份
resourcemanager最好单独出来避免与nodemanager在同一台机器
4)注意
hadoop完全分布式环境启动注意 hdfs的启动和关闭可以在任意节点进行控制: start-dfs.sh或stop-dfs.sh
yarn的启动和关闭必须在主节点上进行控制:start-yarn.sh或stop-yarn.sh
(必须在resourcemanager节点控制)
2、Windows下环境开发配置
1)环境变量配置
解压hadoop压缩包,此处我的版本为hadoop2.7.6版本
E:\hadoop\hadoop-2.7.6
配置windows环境变量,“我的电脑”-》属性-》高级配置-》环境变量配置,添加系统环境变量
HADOOP_HOME=E:\hadoop\hadoop-2.7.6
修改系统变量Path,其后追加(冒号分隔)
Path=。。。;%HADOOP_HOME%\bin
2)hadoop之windows插件配置
将《windows下hadoop-2.7.4的hadoop.dll以及winutils.rar》解压获得hadoop.dll以及winutils.exe两个插件
将hadoop.dll插件放在windows的system32之下,winutils拷贝至hadoop的安装目录的bin目录下
拷贝hadoop.dll至 C:\Windows\System32 拷贝winutils.exe至
E:\hadoop\hadoop-2.7.6\bin
3)Eclipse插件配置
拷贝Eclipse的hadoop连接插件到eclipse的安装目录
拷贝hadoop-eclipse-plugin-2.7.5.jar至E:\WorkSpace\eclipse\plugins目录
Eclipse安装目录根据自己实际位置进行配置
打开Eclipse,Window-》preferences-》搜索hadoop Map/Reduce,添加hadoop的安装目录
E:\hadoop\hadoop-2.7.6
配置Linux中实际的开发环境,包括MapReduce以及YARN地址配置,方式:Window-》show View-》Other然后搜索:
Map/Reduce Localtions
在弹出的视图中右键鼠标,点击“New Location”
然后在弹出的窗口中配置:
Location name: 随意配置一个具有含义的连接名称 Map/Reduce(V2)Master:
此处配置Yarn暴露的地址(见yarn-site.xml配置)和端口9001 DFS
Master:此处配置namenode的主机地址以及端口9000
注意:这里如果配置的host如果为域名,那么必须在WIndows的hosts文件中进行域名映射
打开Project explorer视图,可看到DFS Locations多出了一个hadoop配置,这就是我们刚刚配置的Location name。
在这里我们可以通过刷新改位置信息,实时看到我们通过API或者通过linux上传的文件信息。刷新eclipse查看上传的文件
查看文件
二、Hadoop依赖库配置
1、项目jar的构建
1)新建Java项目Hadoop-DFS01
2)新建main函数入口类
```java
/**
* @文件名: Driver.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Driver {
public static void main(String[] args) {
}
}
3)选择项目树-》属性-》Build Path-》Configure Build Path… -》Libraries-》Add Library-》User Library
选择并新建用户库(第一次没有创建用户库的情况下)
我们创建4个库,包括Hadoop的四个核心组件:
Common:通信协议和工具类,所有类型的开发都需要用到RPC协议以及工具库
HDFS:分布式文件系统库,涉及到文件系统的程序都需要
MapReduce:分布式计算程序相关库,一般的MapReduce程序开发核心库
YARN:分布式计算资源调度库
我们先创建4个库,但是这里我们只需要使用Common和HDFS即可,因为我们这里只做HDFS程序开发。其他库是为MapReduce程序开发做准备而准备的库
选择安装版本的hadoop2.7.6/share/hadoop/common外部的几个jar包和hadoop2.7.6/share/hadoop/common/lib下的所有jar包
新建HDFS库目录,添加E:\hadoop\hadoop-2.7.6\share\hadoop\hdfs下的jar包以及E:\hadoop\hadoop-2.7.6\share\hadoop\hdfs\lib下所有jar包
新建MapReduce库,选择E:\hadoop\hadoop-2.7.6\share\hadoop\mapreduce下的jar包以及E:\hadoop\hadoop-2.7.6\share\hadoop\mapreduce\lib下所有jar包
新建yarn库,选择E:\hadoop\hadoop-2.7.6\share\hadoop\yarn目录下jar以及E:\hadoop\hadoop-2.7.6\share\hadoop\yarn\lib下所有jar包
最后,所有的库建立完成如下:
点击完成,选择common和hdfs库即可(正如我刚说的,我们这里只开发hdfs程序只需要common公共库以及hdfs库即可)
三、HDFS程序开发
这里我们主要讲解的使用hadoop的原生jar包开发,如果使用maven就更简单,所以这里不再对maven配置进行说明
1、项目开发说明
关于HDFS最核心的文件操作类就是FileSystem接口类,通过它你可以操作本地文件系统或者HDFS,如果为空构造函数则操作的就是本地文件系统,文件得根目录就是你程序所在的磁盘的根目录,如果构造函数包括了一个Configure的类则为HDFS文件的操作。
1)、FileSystem与Configuration的分析
/**
* Returns the configured filesystem implementation.
* @param conf the configuration to use
*/
public static FileSystem get(Configuration conf) throws IOException {
return get(getDefaultUri(conf), conf);
}
如果使用的以上的接口获取的位本地文件系统接口,API操作的时候是以程序所在目录的根目录为HDFS的“/”目录,如程序在D盘,上传到根目录为D:/,如果是linux系统配置的单机版,则使用的hadoop的本地文件系统
另一个带参数的的单例构造方法
public static FileSystem get(URI uri, Configuration conf) throws IOException {
String scheme = uri.getScheme();
String authority = uri.getAuthority();
if (scheme == null && authority == null) { // use default FS
return get(conf);
}
if (scheme != null && authority == null) { // no authority
URI defaultUri = getDefaultUri(conf);
if (scheme.equals(defaultUri.getScheme()) // if scheme matches default
&& defaultUri.getAuthority() != null) { // & default has authority
return get(defaultUri, conf); // return default
}
}
String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme);
if (conf.getBoolean(disableCacheName, false)) {
return createFileSystem(uri, conf);
}
return CACHE.get(uri, conf);
}
该接口第一个参数就是HDFS暴露的接口地址,如:hfds://hadoop01:9000,这个接口说明是连接到真实HDFS的接口,上传的文件和下载文件是一个HDFS的根为基础
第三个带参数的单例构造方法
public static FileSystem get(final URI uri, final Configuration conf,
final String user) throws IOException, InterruptedException {
String ticketCachePath =
conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH);
UserGroupInformation ugi =
UserGroupInformation.getBestUGI(ticketCachePath, user);
return ugi.doAs(new PrivilegedExceptionAction<FileSystem>() {
@Override
public FileSystem run() throws IOException {
return get(uri, conf);
}
});
}
该参数多个一个user,说明连接真实的HDFS时候使用的用户名为hadoop,测试环境下如果在windows上调试如果没有该参数,也没有通过jvm参数设置HADOOP_USER_NAME参数值,那么默认使用的用户为windows用户名(比如登录windows的用户名Administrator),测试时候会报权限错误;如果没有传递user参数而且将开发的代码打包提交到linux下,然后运行,那么则使用的当前linux的用户名(不会像windows一样报错,但是要保证linux的用户是hadoop的用户且有读写权限)
2)默认的配置加载顺序
在hadoop安装的时候,我们环境中使用的配置是:hadoop安装目录/etc/hadoop/hdfs-site.xml, 这里面配置的是hadoop通过脚本上传的默认参数,如包括副本数,那么在开发环境中,我们使用什么配置文件控制hdfs相关参数呢?首先在导入的hadoop的hdfs的jar包中可以看到如下配置文件:
也就是说,开发的程序jar包中Configuration类首先会从依赖的hadoop-hdfs-2.7.6.jar包中的hdfs-default.xml中加载相关配置,同时我们可以拷贝一份hdfs-default.xml到我们的应用程序目录,然后修改对应参数(比如replication的副本数测试)
<property>
<name>dfs.replication</name>
<value>3</value>
<description>Default block replication.
The actual number of replications can be specified when the file is created.
The default is used if replication is not specified in create time.
</description>
</property>
可以发现Configuration的配置加载类顺序为: 依赖的hadoop-hdfs-2.7.6.jar 》本应用程序目录的hdfs-default.xml 也就是说应用程序的配置生效,当然也可把应用程序目录的hdfs-default.xml改为hdfs-site.xml,Configuration会先加载依赖包的hdfs-default.xml,然后到应用程序目录下找hdfs-default.xml或hdfs-site.xml的配置文件是否存在,存在则读取配置并覆盖依赖包中加载的配置,否则如果程序中通过Configuration的set接口配置的参数会覆盖依赖库hadoop-hdfs-2.7.6.jar中的默认配置或应用程序中的hdfs-default.xml的配置,所以总结开发程序中的参数优先级(非加载顺序)如下:
A、通过Configuration的set参数配置对应的参数优先级最高
B、通过应用程序目录下的hdfs-site.xml或hdfs-default.xml配置文件的应用程序参数优先级其次
C、依赖包中的hadoop-hdfs-2.7.6.jar包中的默认的配置文件hdfs-default.xml指定的参数最低
2、eclipse开发环境默认用户配置
首先,我们先测试一个文件文件上传,我们在D盘下创建一个文件D:/测试文件.txt,文件内容如下:
接下来,我们使用不指定用户名且在开发环境(windows下)中直接使用run as的方式运行hadoop程序的方式进行如下代码的测试,那么会发生什么事情呢?
package com.easystudy;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
/**
* @文件名: Driver.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Driver {
public static void main(String[] args) throws IOException, URISyntaxException {
// 使用默认配置创建hdfs文件系统
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop01:9000"), conf);
// 将文件上传至根目录
fs.copyFromLocalFile(new Path("D:\\测试文件.txt"), new Path("/"));
// 关闭文件系统
fs.close();
}
}
发生错误如下:
Exception in thread “main”
org.apache.hadoop.security.AccessControlException: Permission denied:
user=Administrator, access=WRITE,
inode="/":hadoop:supergroup:drwxr-xr-x
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:308)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:214)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1752)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1736)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkAncestorAccess(FSDirectory.java:1719)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInternal(FSNamesystem.java:2541)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInt(FSNamesystem.java:2476)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFile(FSNamesystem.java:2360)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.create(NameNodeRpcServer.java:624)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.create(ClientNamenodeProtocolServerSideTranslatorPB.java:398)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocolServerServer.call(RPC.java:982)
at org.apache.hadoop.ipc.Server$HandlerHandlerHandler.run(Server.java:2213)
原因:
这个错误就是开发环境用户配置文件,我们有如下3中方式配置JVM的hadoop使用的用户HADOOP_USER_NAME(注意:这是是jvm参数不是应用程序使用的参数)
解决方法
(1)使用eclipse的运行参数指定jvm参数
-DHADOOP_USER_NAME=hadoop
参数-D表示jvm参数指定,后面跟key=value形式的键值对形式,参数名为HADOOP_USER_NAME,参数值为hadoop(我创建的linux的hadoop账户名就是hadoop),然后再次运行即可,刷新左侧树上的节点查看根目录文件是否上传成功
因为上传的是中文,看上去是乱码,这里我们先忽略只关注上传成功结果即可!使用web查看文件系统也可以看到上传成功:utilities-》Browser the file system然后输入根目录“/”
(2)使用Java的系统类指定jvm参数
修改代码如下:
package com.easystudy;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
/**
* @文件名: Driver.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Driver {
public static void main(String[] args) throws IOException, URISyntaxException {
// 使用jvm系统类指定hadoop运行的用户名
System.setProperty("HADOOP_USER_NAME", "hadoop");
// 使用默认配置创建hdfs文件系统
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop01:9000"), conf);
// 将文件上传至根目录
fs.copyFromLocalFile(new Path("D:\\测试文件.txt"), new Path("/测试文件2.txt"));
// 关闭文件系统
fs.close();
}
}
可以看到多了一行系统环境变量设置
// 使用jvm系统类指定hadoop运行的用户名
System.setProperty("HADOOP_USER_NAME", "hadoop");
运行结果如下所示
上传后,可以看到多了一个文件“测试文件2.txt”
以上的URI配置可以直接通过Configuration进行配置
/**
* @文件名: Driver.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Driver {
public static void main(String[] args) throws IOException, URISyntaxException {
System.setProperty("HADOOP_USER_NAME", "hadoop");
// 使用默认配置创建hdfs文件系统
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://hadoop01:9000");
FileSystem fs = FileSystem.get(conf);
// 将文件上传至根目录
fs.copyFromLocalFile(new Path("D:\\测试文件.txt"), new Path("/测试文件3.txt"));
// 关闭文件系统
fs.close();
}
}
(3)程序中直接指定用户名
修改程序如下所示
package com.easystudy;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
/**
* @文件名: Driver.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Driver {
public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException {
// 使用默认配置创建hdfs文件系统
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://hadoop01:9000"), conf, "hadoop");
// 将文件上传至根目录
fs.copyFromLocalFile(new Path("D:\\测试文件.txt"), new Path("/测试文件4.txt"));
// 关闭文件系统
fs.close();
}
}
可以看到,我们通过最后一个参数user直接指定hadoop使用用户为hadoop,二不用去设置JVM的环境变量!刷新结果如下
3、文件操作单例类
package com.easystudy.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
/**
* @文件名: HDFSUtil.java
* @功 能: TODO(HDFS操作工具类)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class HdfsUtil {
private String uri = "";
private String user = "";
private FileSystem fileSystem = null;
private static HdfsUtil instance;
private HdfsUtil(String uri, String user){
this.uri = uri;
this.user = user;
}
/**
* @功 能: TODO(获取文件操作工具实例)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public synchronized static HdfsUtil getInstance(String uri, String user){
if(null == instance){
instance = new HdfsUtil(uri, user);
}
if(null != instance){
if(!instance.open()){
instance = null;
}
}
return instance;
}
/**
* @功 能: TODO(连接HDFS文件系统)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
private boolean open(){
Configuration conf = new Configuration();
//conf.set("fs.defaultFS", uri);
try {
fileSystem = FileSystem.get(new URI(uri), conf, user);
return null != fileSystem;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return false;
}
/**
* @功 能: TODO(关闭连接)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public void close(){
if (fileSystem != null) {
try {
fileSystem.close();
fileSystem = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用方式:
package com.easystudy;
import com.easystudy.util.HdfsUtil;
/**
* @文件名: Demon.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Demon {
public static void main(String[] args) {
// 获取操作实例
HdfsUtil hdfs = HdfsUtil.getInstance("hdfs://hadoop01:9000", "hadoop");
if (hdfs != null) {
// 文件操作
// 此处调用封装类的实现方法即可
// 关闭文件
hdfs.close();
}
}
}
4、创建文件夹
/**
* @功 能: TODO(在dfs中级联创建目录)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean createFolder(String folder){
if (fileSystem == null) {
return false;
}
try {
if(!fileSystem.exists(new Path(folder))){
return fileSystem.mkdirs(new Path(folder));
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
如果文件夹存在则无需创建,不存在则创建,两者情况都返回成功,除非创建失败!
5、上传文件
/**
* @功 能: TODO(上传文件到HDFS文件服务器)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean upload(String src, String dest){
if (fileSystem == null) {
return false;
}
try {
fileSystem.copyFromLocalFile(new Path(src), new Path(dest));
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
6、下载文件
/**
* @功 能: TODO(从HDFS下载文件到本地)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean download(String src, String dest){
if (fileSystem == null) {
return false;
}
try {
fileSystem.copyToLocalFile(new Path(src), new Path(dest));
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
可以看到下载的文件和下载的一个crc文件完整性校验文件(用于与hadoop中存储的块的meta文件进行校验,检查是否损坏)!
7、创建0字节的新文件
/**
* @功 能: TODO(一个创建0字节且不存在的文件)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean createFileIfNotExist(String path){
if (fileSystem == null) {
return false;
}
try {
if(fileSystem.exists(new Path(path))){
return false;
}
return fileSystem.createNewFile(new Path(path));
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
创建结果
8、删除文件
/**
* @功 能: TODO(从HDFS中删除一个存在的文件)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean deleteFile(String filePath){
if (fileSystem == null) {
return false;
}
try {
return fileSystem.delete(new Path(filePath), false);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
9、删除目录(递归目录,如果目录下有文件则删除文件)
/**
* @功 能: TODO(清空目录)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean deleteDirectory(String dir){
if (fileSystem == null) {
return false;
}
try {
FileStatus[] status = fileSystem.listStatus(new Path(dir));
if (null == status) {
fileSystem.delete(new Path(dir), false);
} else {
for(FileStatus fs : status){
if (fs.isFile()) {
fileSystem.delete(fs.getPath(), false);
} else {
deleteDirectory(fs.toString());
}
}
fileSystem.delete(new Path(dir), true);
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
10、文件重名名或文件位置移动
/**
* @功 能: TODO(将已经存在的文件或文件夹重命名为另一个文件或文件夹)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean rename(String oldPath, String newPath){
if (fileSystem == null) {
return false;
}
try {
if (!fileSystem.exists(new Path(oldPath))) {
return false;
}
if (fileSystem.exists(new Path(newPath))) {
return false;
}
return fileSystem.rename(new Path(oldPath), new Path(newPath));
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
11、列举目录下所有文件
/**
* @功 能: TODO(列举目录下所有文件)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public String[] listFiles(String dir){
List<String> files = new ArrayList<String>();
if (fileSystem == null) {
return toArray(files);
}
try {
RemoteIterator<LocatedFileStatus> it = fileSystem.listFiles(new Path(dir), true);
if (it != null) {
while (it.hasNext()) {
LocatedFileStatus st = (LocatedFileStatus) it.next();
if (st != null) {
files.add(st.getPath().toString());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return toArray(files);
}
/**
* @功 能: TODO(列表转数组)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public String[] toArray(List<String> files){
String[] arr = new String[files.size()];
int i = 0;
for (String st: files) {
arr[i++] = st;
}
return arr;
}
12、二进制文件读取
/**
* @功 能: TODO(打开文件获取文件输入流)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public FSDataInputStream Open(String file){
if (fileSystem == null) {
return null;
}
try {
return fileSystem.open(new Path(file));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @功 能: TODO(从打开的文件中读取一行)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
@SuppressWarnings("deprecation")
public String readLine(FSDataInputStream in){
try {
return in.readLine();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @功 能: TODO(关闭文件输入流)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public void close(FSDataInputStream in){
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
13、二进制写文件
/**
* @功 能: TODO(通过二进制流形式读取文件并上传到HDFS)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @说 明:
* @历 史:aaa@qq.com 1.0
*/
public boolean write(File file, String newFilePath){
if (fileSystem == null) {
return false;
}
FileInputStream in = null;
FSDataOutputStream out = null;
try {
if (fileSystem.exists(new Path(newFilePath))) {
return false;
}
in = new FileInputStream(file);
out = fileSystem.create(new Path(newFilePath), false);
byte[] buf = new byte[1024*1024];
int length = 0;
while ((length = in.read(buf, 0, 1024*1024)) > 0) {
out.write(buf, 0, length);
}
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return false;
}
以上接口的测试用例如下:
package com.easystudy;
import java.io.File;
import com.easystudy.util.HdfsUtil;
/**
* @文件名: Demon.java
* @功 能: TODO(用一句话描述该文件做什么)
* @作 者: aaa@qq.com
* @日 期: 2019年12月18日
* @版 本: V1.0
*/
public class Demon {
public static void main(String[] args) {
HdfsUtil hdfs = HdfsUtil.getInstance("hdfs://hadoop01:9000", "hadoop");
if (hdfs != null) {
hdfs.createFolder("/001");
hdfs.createFolder("/001/002/003");
hdfs.upload("d:\\article.txt", "/001/002");
hdfs.upload("d:\\article.txt", "/001/002/003");
//hdfs.download("/001/article.txt", "D:\\english.txt");
//hdfs.createFileIfNotExist("/001/001.txt");
//hdfs.deleteFile("/001/001.txt");
//hdfs.deleteDirectory("/001");
//hdfs.rename("/001/002/article.txt", "/001/article2.txt");
// String[] files = hdfs.listFiles("/001");
// for (String string : files) {
// System.out.println(string);
// }
// FSDataInputStream in = hdfs.Open("/001/article2.txt");
// System.out.println(hdfs.readLine(in));
// hdfs.close(in);
hdfs.write(new File("d:\\article.txt"), "/001/1.txt");
hdfs.close();
}
}
}
上一篇: HDFS基本原理--工作机制
推荐阅读
-
《深入理解大数据:大数据处理与编程实践》一一3.5 HDFS基本编程接口与示例...
-
11、HDFS编程案例
-
HDFS编程实践
-
SSM案例-企业权限系统(11)- 权限操作- spring security 入门
-
java11正式发布了,让java代码更完美 博客分类: java java资讯编程
-
Java编程思想-11持有对象
-
《Java编程思想》 第11章 持有对象
-
《Java编程思想》——第11章 持有对象(容器类)
-
JavaScript DOM 编程艺术 阅读总结 (第十二章 实践案例代码)
-
CMDN CLUB 第11期:打造卓越Metro用户体验(上海站)-WP7应用与游戏开发案例分享