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(用一句话描述该文件做什么)
* @作    者: lixx2048@163.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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$ClientNamenodeProtocol 2. c a l l B l o c k i n g M e t h o d ( C l i e n t N a m e n o d e P r o t o c o l P r o t o s . j a v a ) a t o r g . a p a c h e . h a d o o p . i p c . P r o t o b u f R p c E n g i n e 2.callBlockingMethod(ClientNamenodeProtocolProtos.java) at org.apache.hadoop.ipc.ProtobufRpcEngine 2.callBlockingMethod(ClientNamenodeProtocolProtos.java)atorg.apache.hadoop.ipc.ProtobufRpcEngineServer P r o t o B u f R p c I n v o k e r . c a l l ( P r o t o b u f R p c E n g i n e . j a v a : 616 ) a t o r g . a p a c h e . h a d o o p . i p c . R P C ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616) at org.apache.hadoop.ipc.RPC ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)atorg.apache.hadoop.ipc.RPCServer.call(RPC.java:982)
at org.apache.hadoop.ipc.Server$Handler 1. r u n ( S e r v e r . j a v a : 2217 ) a t o r g . a p a c h e . h a d o o p . i p c . S e r v e r 1.run(Server.java:2217) at org.apache.hadoop.ipc.Server 1.run(Server.java:2217)atorg.apache.hadoop.ipc.ServerHandler 1. r u n ( S e r v e r . j a v a : 2213 ) a t j a v a . s e c u r i t y . A c c e s s C o n t r o l l e r . d o P r i v i l e g e d ( N a t i v e M e t h o d ) a t j a v a x . s e c u r i t y . a u t h . S u b j e c t . d o A s ( S u b j e c t . j a v a : 422 ) a t o r g . a p a c h e . h a d o o p . s e c u r i t y . U s e r G r o u p I n f o r m a t i o n . d o A s ( U s e r G r o u p I n f o r m a t i o n . j a v a : 1758 ) a t o r g . a p a c h e . h a d o o p . i p c . S e r v e r 1.run(Server.java:2213) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:422) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1758) at org.apache.hadoop.ipc.Server 1.run(Server.java:2213)atjava.security.AccessController.doPrivileged(NativeMethod)atjavax.security.auth.Subject.doAs(Subject.java:422)atorg.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1758)atorg.apache.hadoop.ipc.ServerHandler.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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操作工具类)
* @作     者: lixx2048@163.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(获取文件操作工具实例)
     * @作    者: lixx2048@163.com
     * @日    期: 2019年12月18日
     * @说    明:
     * @历    史:lixx2048@163.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文件系统)
     * @作    者: lixx2048@163.com
     * @日    期: 2019年12月18日
     * @说    明:
     * @历    史:lixx2048@163.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(关闭连接)
     * @作    者: lixx2048@163.com
     * @日    期: 2019年12月18日
     * @说    明:
     * @历    史:lixx2048@163.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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中级联创建目录)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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文件服务器)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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下载文件到本地)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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字节且不存在的文件)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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中删除一个存在的文件)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(清空目录)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(将已经存在的文件或文件夹重命名为另一个文件或文件夹)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(列举目录下所有文件)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(列表转数组)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(打开文件获取文件输入流)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(从打开的文件中读取一行)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.com 1.0
      */
     @SuppressWarnings("deprecation")
     public String readLine(FSDataInputStream in){
           try {
                return in.readLine();
           } catch (Exception e) {
                e.printStackTrace();
           }
           return null;
     }
     
     /**
      * @功    能: TODO(关闭文件输入流)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.com 1.0
      */
     public void close(FSDataInputStream in){
           try {
                in.close();
           } catch (Exception e) {
                e.printStackTrace();
           }
     }

13、二进制写文件

     /**
      * @功    能: TODO(通过二进制流形式读取文件并上传到HDFS)
      * @作    者: lixx2048@163.com
      * @日    期: 2019年12月18日
      * @说    明:
      * @历    史:lixx2048@163.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(用一句话描述该文件做什么)
* @作     者: lixx2048@163.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();
           }
     }
}

快来成为我的朋友或合作伙伴,一起交流,一起进步!:
QQ群:961179337
微信:lixiang6153
邮箱:lixx2048@163.com
公众号:IT技术快餐

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝壳里的沙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值