HDFS入门—— HDFS的API操作(图文详解步骤2021)

Posted Leokadia Rothschild

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDFS入门—— HDFS的API操作(图文详解步骤2021)相关的知识,希望对你有一定的参考价值。

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

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

3.1 客户端环境 准备

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

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

在这里插入图片描述

2 ) 配置 HADOOP_HOME 环境 变量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3 ) 配置 Path 环境 变量 。

将HADOOP_HOME目录添加到对应的PATH目录
在这里插入图片描述

在这里插入图片描述
注意: 如果环境变量不起作用,可以 重启电脑 试试。

验证 Hadoop 环境变量是否正常。双击 winutils.exe,如果报如下错误。
在这里插入图片描述
说明缺少微软运行库 (正版系统往往有这个问题) 。 下载微软运行库安装包双击安装即可。

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

创建Maven工程以及进行相关配置
在这里插入图片描述
在这里插入图片描述
进入之后点击Files→Settings
搜索Maven修改Maven配置

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

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置好了后点击ok即可

然后再原配置文件中添加相关依赖
在这里插入图片描述

<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> 

在这里插入图片描述

在项目的 src/main/resources 目录下,新建一个文件,命名为“log4j.properties”,为了打印日志
在这里插入图片描述
在新建的文件中填入以下内容

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 

在这里插入图片描述

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

在这里插入图片描述

6 ) 创建 HdfsClient 类

在这里插入图片描述

在这里插入图片描述
创建好了客户端类,接下来写代码操作远程的服务器集群集群

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"));

    }

}

在这里插入图片描述
运行@Test
在这里插入图片描述
成功创建文件夹
在这里插入图片描述

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

先在D盘根目录下创建一个待上传的文件
在这里插入图片描述

在这里插入图片描述
在刚刚的代码中加入如下代码

1 ) 编写源代码

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

在这里插入图片描述
点击运行
上传完毕
在这里插入图片描述

tip:再运行一次
在这里插入图片描述
报异常
原因,再参数中允许覆盖写的false,因此原来Iron_Man.txt存在,却不能覆盖,因此报错,所以常常把是否允许覆盖的参数改为true
在这里插入图片描述

Tip2: 刚刚的操作我们查看源文件:
在这里插入图片描述
发现源文件依旧存在,这个时候我们如果把第一个delSrc参数改为true,再次运行:
在这里插入图片描述
在这里插入图片描述
源文件不见了,源数据被删除

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

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

在resources下新建一个file——hdfs-site.xml
在这里插入图片描述
将下面代码粘贴到里面:(修改副本数为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 优先级高
再创建一个测试文件
在这里插入图片描述
执行上传
在这里插入图片描述
副本数为1
在这里插入图片描述
说明在项目资源目录下用户自定义的配置文件高

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

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

在这里插入图片描述
再运行一遍刚刚的代码
发现Spider_Man.txt副本数变为2了
在这里插入图片描述
说明客户端代码中设置的值 >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)运行结果:

在这里插入图片描述

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

2)运行结果:

运行Test代码,下载成功
在这里插入图片描述
注意:是不是突然发现多了一个crc文件,用于检测传输数据有无发生变化,刚刚参数4设置为false进行了传输文件的校验
如果将最后一个参数改为true
在这里插入图片描述
再次运行:(注意把上次运行的文件删掉)
在这里插入图片描述
发现没有校验文件

然后第一个参数,如果设置为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)运行结果:

这里不再演示删除文件了
对于删除空目录
博主创建了一个测试空目录
在这里插入图片描述
运行代码:
在这里插入图片描述
成功删除
在这里插入图片描述
对于非空目录Marvel:(注意要递归删除,第二个参数设置为true)
在这里插入图片描述
运行下面的代码
在这里插入图片描述
递归删除成功
在这里插入图片描述

3.2.5 文件的更名和移动

新建一个测试文件夹和相应的测试文件
在这里插入图片描述
在这里插入图片描述

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)运行结果:

运行第一条,注释后两条:
在这里插入图片描述
在这里插入图片描述
运行第二条:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行第三条:
在这里插入图片描述

在这里插入图片描述

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)运行结果:

在这里插入图片描述

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的API操作(图文详解步骤2021)的主要内容,如果未能解决你的问题,请参考以下文章

HDFS入门—— DataNode(图文详解步骤2021)

图文详解HDFS工作机制

图文详解HDFS基本原理

图文详解HDFS 系统架构与文件数据读写流程

Hadoop HDFS 实现原理图文详解

HDFS读写流程图文详解,及职责详解