HDFS入门(三)—— HDFS的API操作

刚刚(二)讲的是用Shell/Hadoop fs/HDFS/dfs的一些相关操作,相当于是在集群内部,跟集群的一些客户端打交道,这章讲的是:我们希望在Windows环境(办公环境)对远程的集群进行一个客户端访问,于是现在就在Windows环境上写代码,写HDFS客户端代码,远程连接上集群,对它们进行增删改查相关操作。

hdfs搭建_maven


文章目录

  • HDFS入门(三)—— HDFS的API操作
  • 3.1 客户端环境 准备
  • 1) 下载 hadoop-3.1.0 (windows版)到非中文路径 (比如E:\Sofware)
  • 2 ) 配置 HADOOP_HOME 环境 变量
  • 3 ) 配置 Path 环境 变量 。
  • 4 ) 在 IDEA 中 创建一个 Maven 工程 HdfsClientDemo ,并导入相应的依赖坐标+ 日志添加
  • 5 ) 创建包名 :com.leokadia.hdfs
  • 6 ) 创建 HdfsClient 类
  • 7 ) 执行 程序
  • 3.2 HDFS 的 API 案例实操
  • 3.2.1 用客户端远程创建目录
  • 3.2.2 HDFS 用客户端上传文件(测试 参数优先级 )
  • 1 ) 编写源代码
  • 2 ) 将 hdfs-site.xml 拷贝到项目的 resources 资源目录下
  • 3 )总结: 参数 优先级
  • 3.2.3 HDFS 文件下载
  • 1 ) 编写源代码
  • 2)运行结果:
  • 2)运行结果:
  • 3.2.4 HDFS 删除 文件 和目录
  • 1 ) 编写源代码(运行时注意注释掉其余的)
  • 2)运行结果:
  • 3.2.5 文件的更名和移动
  • 1 ) 编写源代码
  • 2)运行结果:
  • 3.2.6 通过客户端的方式获取 HDFS 文件 详情信息
  • 1 ) 编写源代码
  • 2)运行结果:
  • 3.2.7 HDFS 文件和文件夹判断
  • 1 ) 编写源代码
  • 2)运行结果:


3.1 客户端环境 准备

想让我们的windows能够连接上远程的Hadoop集群,windows里面也得有相关的环境变量

1) 下载 hadoop-3.1.0 (windows版)到非中文路径 (比如E:\Sofware)

hdfs搭建_hadoop_02

2 ) 配置 HADOOP_HOME 环境 变量

hdfs搭建_hdfs_03


hdfs搭建_大数据_04


hdfs搭建_hadoop_05

3 ) 配置 Path 环境 变量 。

将HADOOP_HOME目录添加到对应的PATH目录

hdfs搭建_大数据_06

hdfs搭建_hdfs_07


注意: 如果环境变量不起作用,可以 重启电脑 试试。验证 Hadoop 环境变量是否正常。双击 winutils.exe,如果报如下错误。

hdfs搭建_hdfs_08


说明缺少微软运行库 (正版系统往往有这个问题) 。 下载微软运行库安装包双击安装即可。

4 ) 在 IDEA 中 创建一个 Maven 工程 HdfsClientDemo ,并导入相应的依赖坐标+ 日志添加

创建Maven工程以及进行相关配置

hdfs搭建_hdfs搭建_09


hdfs搭建_hadoop_10


进入之后点击Files→Settings

搜索Maven修改Maven配置

注意:这里的Maven博主没有用系统默认的那个,那个下载地址在国外,下载依赖十分慢,同时那个自带的Maven跟很多的jar包的都不兼容,不好用,博主重新从官网下载了个Maven并配置了
具体配置步骤请参考博客
HDFS的API环境准备小知识——Maven 安装与配置

hdfs搭建_hadoop_11

hdfs搭建_maven_12


hdfs搭建_maven_13


hdfs搭建_大数据_14


配置好了后点击ok即可然后再原配置文件中添加相关依赖

hdfs搭建_hadoop_15

<dependencies> 
    <dependency> 
        <groupId>org.apache.hadoop</groupId> 
        <artifactId>hadoop-client</artifactId> 
        <version>3.1.3</version> 
    </dependency> 
    <dependency> 
        <groupId>junit</groupId> 
        <artifactId>junit</artifactId> 
        <version>4.12</version> 
    </dependency> 
    <dependency> 
        <groupId>org.slf4j</groupId> 
        <artifactId>slf4j-log4j12</artifactId> 
        <version>1.7.30</version> 
    </dependency> 
</dependencies>

hdfs搭建_hadoop_16

在项目的 src/main/resources 目录下,新建一个文件,命名为“log4j.properties”,为了打印日志

hdfs搭建_hdfs_17


在新建的文件中填入以下内容

log4j.rootLogger=INFO, stdout   
log4j.appender.stdout=org.apache.log4j.ConsoleAppender   
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout   
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n   
log4j.appender.logfile=org.apache.log4j.FileAppender   
log4j.appender.logfile.File=target/spring.log   
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout   
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

hdfs搭建_hadoop_18

5 ) 创建包名 :com.leokadia.hdfs

hdfs搭建_大数据_19

6 ) 创建 HdfsClient 类

hdfs搭建_hadoop_20

hdfs搭建_hadoop_21


创建好了客户端类,接下来写代码操作远程的服务器集群集群

7 ) 执行 程序

客户端去操作 HDFS 时,是有一个用户身份的。默认情况下,HDFS 客户端 API 会从采用 Windows 默认用户访问 HDFS,会报权限异常错误。所以在访问 HDFS 时,一定要配置用户。

org.apache.hadoop.security.AccessControlException: Permission denied: 
user=56576, access=WRITE, 
inode="/xiyou/huaguoshan":atguigu:supergroup:drwxr-xr-x

3.2 HDFS 的 API 案例实操

3.2.1 用客户端远程创建目录

package com.leokadia.hdfs;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @author sa
 * @create 2021-05-04 16:37
 *
 *
 * 客户端代码常用套路
 * 1、获取一个客户端对象
 * 2、执行相关的操作命令
 * 3、关闭资源
 * HDFS zookeeper
 */
public class HdfsClient {

    private FileSystem fs;

    @Before
    public void init() throws IOException, URISyntaxException, InterruptedException {

        //连接集群的nn地址
        URI uri = new URI("hdfs://hadoop102:8020");

        //创建一个配置文件
        Configuration configuration = new Configuration();

        //用户
        String user = "leokadia";

        // 1 获取客户端对象
        fs = FileSystem.get(uri, configuration, user);
    }

    @After
    public void close() throws IOException {
        // 3 关闭资源
        fs.close();
    }

    @Test
    public void testmkdir() throws URISyntaxException,IOException,InterruptedException {
        // 2 创建一个文件夹
        fs.mkdirs(new Path("/Marvel/Avengers"));

    }

}

hdfs搭建_hadoop_22


运行@Test

hdfs搭建_maven_23


成功创建文件夹

hdfs搭建_大数据_24

3.2.2 HDFS 用客户端上传文件(测试 参数优先级 )

先在D盘根目录下创建一个待上传的文件

hdfs搭建_hdfs搭建_25

hdfs搭建_hdfs搭建_26


在刚刚的代码中加入如下代码

1 ) 编写源代码
// 上传
    @Test
    public void testPut() throws IOException {
        //参数解读:参数一:表示删除原数据;参数二:是否允许覆盖;参数三:原数据路径;参数四:目的地路径
        fs.copyFromLocalFile(false,false,new Path("D:\\Iron_Man.txt"),new Path("hdfs://hadoop102/Marvel/Avengers"));
    }

hdfs搭建_hdfs搭建_27


点击运行

上传完毕

hdfs搭建_maven_28

tip:再运行一次

hdfs搭建_大数据_29


报异常


原因,再参数中允许覆盖写的false,因此原来Iron_Man.txt存在,却不能覆盖,因此报错,所以常常把是否允许覆盖的参数改为true


hdfs搭建_maven_30

Tip2: 刚刚的操作我们查看源文件:

hdfs搭建_hdfs_31


发现源文件依旧存在,这个时候我们如果把第一个delSrc参数改为true,再次运行:


hdfs搭建_hdfs_32


hdfs搭建_hdfs_33


源文件不见了,源数据被删除

2 ) 将 hdfs-site.xml 拷贝到项目的 resources 资源目录下

已知服务器的默认配置 (xxx-default.xml) 中的副本数是3,现在resources下新建一个file——hdfs-site.xml修改副本数
测试二者的优先级

在resources下新建一个file——hdfs-site.xml

hdfs搭建_hdfs_34


将下面代码粘贴到里面:(修改副本数为1)

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 
 
<configuration> 
  <property> 
   <name>dfs.replication</name>       
    <value>1</value> 
  </property> 
</configuration>

如果再上传一个文件,它的副本数为1,说明 resources 资源目录下的hdfs-site.xml 优先级高

再创建一个测试文件

hdfs搭建_大数据_35


执行上传

hdfs搭建_hadoop_36


副本数为1

hdfs搭建_maven_37


说明在项目资源目录下用户自定义的配置文件高

再测试客户端代码中配置副本的值的优先级:
在源代码中加上:

configuration.set("dfs.replication","2");

hdfs搭建_大数据_38


再运行一遍刚刚的代码

发现Spider_Man.txt副本数变为2了

hdfs搭建_hdfs搭建_39


说明客户端代码中设置的值 >ClassPath 下的用户自定义配置文件

3 )总结: 参数 优先级

参数优先级排序:
(1)客户端代码中设置的值 >
(2)ClassPath 下的用户自定义配置文件 >
(3) 然后是服务器的自定义配置 (xxx-site.xml) >
(4) 服务器的默认配置 (xxx-default.xml)

3.2.3 HDFS 文件下载

1 ) 编写源代码
@Test 
// 文件下载
    @Test
    public void testGet() throws IOException {
        //参数解读:参数一: boolean delSrc 指是否将原文件删除;参数二:Path src 指要下载的原文件路径
        // 参数三:Path dst 指将文件下载到的目标地址路径;参数四:boolean useRawLocalFileSystem 是否开启文件校验
        fs.copyToLocalFile(false, new Path("hdfs://hadoop102/Marvel/Avengers/Iron_Man.txt"), new Path("D:\\Robert.txt"), false);
    }
2)运行结果:

hdfs搭建_hdfs_40

注意:如果执行上面代码,下载不了文件,有可能是你电脑的微软支持的运行库少,需要安装一下微软运行库。

2)运行结果:

运行Test代码,下载成功

hdfs搭建_hdfs搭建_41


注意:是不是突然发现多了一个crc文件,用于检测传输数据有无发生变化,刚刚参数4设置为false进行了传输文件的校验

如果将最后一个参数改为true

hdfs搭建_hdfs_42


再次运行:(注意把上次运行的文件删掉)

hdfs搭建_大数据_43


发现没有校验文件

然后第一个参数,如果设置为true,则HDFS上的文件会消失,即源文件删除

3.2.4 HDFS 删除 文件 和目录

1 ) 编写源代码(运行时注意注释掉其余的)
// 删除
    @Test
    public void testRm() throws IOException {

        // 参数解读:参数1:要删除的路径; 参数2 : 是否递归删除
        // 删除文件(不再演示了)
        fs.delete(new Path("/jdk-8u212-linux-x64.tar.gz"),false);

        // 删除空目录
        fs.delete(new Path("/delete_test_empty"), false);

        // 删除非空目录
        fs.delete(new Path("/Marvel"), true);
    }
2)运行结果:

这里不再演示删除文件了

对于删除空目录

博主创建了一个测试空目录

hdfs搭建_maven_44


运行代码:

hdfs搭建_hadoop_45


成功删除

hdfs搭建_hdfs搭建_46


对于非空目录Marvel:(注意要递归删除,第二个参数设置为true)

hdfs搭建_hdfs_47


运行下面的代码

hdfs搭建_hdfs_48


递归删除成功

hdfs搭建_maven_49

3.2.5 文件的更名和移动

新建一个测试文件夹和相应的测试文件

hdfs搭建_hadoop_50


hdfs搭建_maven_51

1 ) 编写源代码
// 文件的更名和移动
    @Test
    public void testmv() throws IOException {
        // 参数解读:参数1 :原文件路径; 参数2 :目标文件路径
        // 对文件名称的修改
        fs.rename(new Path("/move/from.txt"), new Path("/move/new.txt"));

        // 文件的移动和更名
        fs.rename(new Path("/move/new.txt"),new Path("/to.txt"));

        // 目录更名
        fs.rename(new Path("/move"), new Path("/shift"));

    }
2)运行结果:

运行第一条,注释后两条:

hdfs搭建_maven_52


hdfs搭建_hdfs搭建_53


运行第二条:

hdfs搭建_maven_54


hdfs搭建_大数据_55


hdfs搭建_hadoop_56


运行第三条:

hdfs搭建_hdfs搭建_57

hdfs搭建_hadoop_58

3.2.6 通过客户端的方式获取 HDFS 文件 详情信息

查看文件名称、权限、长度、块信息

1 ) 编写源代码
// 获取文件详细信息
    @Test
    public void fileDetail() throws IOException {

        // 获取所有文件信息
        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

        // 遍历文件
        while (listFiles.hasNext()) {
            LocatedFileStatus fileStatus = listFiles.next();

            System.out.println("==========" + fileStatus.getPath() + "=========");
            System.out.println(fileStatus.getPermission());
            System.out.println(fileStatus.getOwner());
            System.out.println(fileStatus.getGroup());
            System.out.println(fileStatus.getLen());
            System.out.println(fileStatus.getModificationTime());
            System.out.println(fileStatus.getReplication());
            System.out.println(fileStatus.getBlockSize());
            System.out.println(fileStatus.getPath().getName());

            // 获取块信息
            BlockLocation[] blockLocations = fileStatus.getBlockLocations();

            System.out.println(Arrays.toString(blockLocations));

        }
    }
2)运行结果:

hdfs搭建_大数据_59

3.2.7 HDFS 文件和文件夹判断

1 ) 编写源代码
// 判断是文件夹还是文件
    @Test
    public void testFile() throws IOException {

        FileStatus[] listStatus = fs.listStatus(new Path("/"));

        for (FileStatus status : listStatus) {

            if (status.isFile()) {
                System.out.println("文件:" + status.getPath().getName());
            } else {
                System.out.println("目录:" + status.getPath().getName());
            }
        }
    }
2)运行结果:

hdfs搭建_hdfs_60