文章目录

  • 一.实验环境准备
  • 1.在windows环境当中安装hadoop bin,maven,配置HADOOP_HOME,MVN_HOME,Path环境变量。
  • 2.配置settings文件
  • 3.IDEA中创建maven工程
  • 4.修改maven库位置(将maven本地库加载到IDEA)
  • 5.建立子项目
  • 6.如果Eclipse/Idea打印不出日志,在控制台上只显示:
  • 二.实验操作
  • 1.说明
  • (1) 在 Java 中操作 HDFS, 主要涉及以下类:
  • (2)IDEA相关快捷键
  • (3)获取` FileSystem `的几种方式
  • 2.创建目录
  • 3.删除目录
  • 4.上传文件(Windows->hdfs)
  • 5.参数的优先级
  • (1)在resource中添加配置文件hdfs-site.xml
  • (2)代码中添加配置
  • 6.文件下载(hdfs->Windows)
  • 7.获取文件详情
  • 8.判断是不是文件


一.实验环境准备

下载对应版本hadoop bin

1.在windows环境当中安装hadoop bin,maven,配置HADOOP_HOME,MVN_HOME,Path环境变量。

HDFS portmap 自带的rpcbind功能 启动不了_apache


HDFS portmap 自带的rpcbind功能 启动不了_hadoop_02

变量值为安装目录(安装目录尽量不含中文和空格)

2.配置settings文件

在apache-maven-3.6.1\conf下可以找到settings文件,打开。
复制第53行

<localRepository>/path/to/local/repo</localRepository>

将它拿到注释外并将中间的内容改成你需要的本地库文件目录路径

<localRepository>F://repository</localRepository>

添加阿里云仓库(大约在150行左右)(要夹在两个mirrors标签之间)

<mirror>
  <id>aliyunmaven</id>
  <mirrorOf>*</mirrorOf>
  <name>阿里云公共仓库</name>
  <url>https://maven.aliyun.com/repository/public</url>
</mirror>

在最后配置jdk,也要夹在两个profiles标签之间(我这里使用的为jdk8)

<!-- java版本 --> 
<profile>
      <id>jdk-1.8</id>
     <activation>
	    <activeByDefault>true</activeByDefault>
        <jdk>1.8</jdk>
     </activation>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
	<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
   </properties>
</profile>

3.IDEA中创建maven工程

Create New Project =>maven(不需要用任何模板)=>Next

HDFS portmap 自带的rpcbind功能 启动不了_hadoop_03

Hadoop作为父项目,finish后删除src文件,将所有的依赖写入父项目中,其他继 承父项目即可。
导入相应的依赖坐标+日志添加(在父项目的pom.xml中添加)

<properties>
    <hadoop.version>2.7.3</hadoop.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
       <!-- <scope>test</scope> -->
    </dependency>
    <!--log4j依赖-->
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
   <!-- <scope>test</scope> -->
</dependency>

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>${hadoop.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>${hadoop.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>${hadoop.version}</version>
    </dependency>
</dependencies>

4.修改maven库位置(将maven本地库加载到IDEA)

File==>setting==>maven(找不到就搜索)

HDFS portmap 自带的rpcbind功能 启动不了_hdfs_04

5.建立子项目

在Project下的Hadoop右击new一个Module,父项目为Hadoop。

HDFS portmap 自带的rpcbind功能 启动不了_hdfs_05


(新项目的pom依赖已继承Hadoop不需要导入)

在新项目的src=>main=>java下创建com.normal.hdfs包(规范),在该包下写相应代码。

6.如果Eclipse/Idea打印不出日志,在控制台上只显示:

log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell).  
log4j:WARN Please initialize the log4j system properly.  
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入

#日志打印入口 
 log4j.rootLogger=INFO, stdout, logfile
 #控制台打印日志的样
 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.FileAppenderlog4j.appender.logfile.File=target/hdfs.log
 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
 log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

二.实验操作

1.说明

(1) 在 Java 中操作 HDFS, 主要涉及以下类:

Configuration 该类的对象封装了客户端或者服务器的配置。

FileSystem 该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作, 通过 FileSystem的静态方法 get 获得该对象。

FileSystem fs = FileSystem.get(conf) get 方法从 conf 中的一个参数fs.defaultFS的配置值判断具体是什么类型的文件系统。 如果我们的代码中没有指定 fs.defaultFS, 并且工程 ClassPath下也没有给定相应的配置, conf中的默认值就来自于 Hadoop 的Jar 包中的 core-default.xml。默认值为 file:///, 则获取的不是一个HDFSFileSystem的实例, 而是一个本地文件系统的客户端对象。

因为Hadoop中关于文件操作类基本上都在org.apache.hadoop.fs包中,这些API的主要作用主要体现在以下操作上:打开文件、读写文件、删除文件。并且,Hadoop类库中最终面向用户提供的接口类是FileSystem,该类是一个抽象类,只能通过get方法得到。

URI称为统一资源标示符,在Hadoop中使用URI路径作为参数(URI中写的是hdfs的地址),其格式是:scheme://authority/path。对于HDFS文件系统,scheme(对应协议名)就是hdfs(对于本地文件系统就是file),authority就是namenode主机名,path就是文件(目录)的路径构成的字符串。一个HDFS目录或者文件,比如/parent/child,可以表示为hdfs://namenode:namenodeport/parent/child,一个namenode名称为Master,对应HDFS的端口号是9000的话,实际上就是hdfs://Master:9000/parent/child

(2)IDEA相关快捷键

自动补全代码:Alt+Enter查看方法中的参数详情:Ctrl+P快速创建构造方法/setter/getter:Alt+Insert提炼全局变量: Ctrl+Alt+F查看源码:Ctrl+鼠标左击

(3)获取FileSystem的几种方式

FileSystem:是客户端(idea)和集群(hdfs)之间的“通道,它是与Hadoop的某一文件系统进行交互的API。

第一种方式

@Test
 public void getFileSystem() throws URISyntaxException, IOException {
   Configuration conf = new Configuration();
   FileSystem fs = FileSystem.get(new URI("hdfs://hadoop01:9000"), conf);
   System.out.println(fs.toString());
 }

(hadoop01是虚拟机主机名,需要在C:\Windows\System32\drivers\etc\hosts下配置主机名与ip地址的映射关系,如:192.168.111.132 hadoop01 )
第二种方式

@Test
public void getFileSystem2() throws URISyntaxException, IOException {
    Configuration conf = new Configuration();
    configuration.set("fs.defaultFS","hdfs://hadoop01:9000");
    FileSystem fs = FileSystem.get(new URI("/"), conf);
    System.out.println(fs.toString());
}

第三种方式

@Test
public void getFileSystem3() throws URISyntaxException, IOException {
 Configuration conf = new Configuration();
 FileSystem fs=FileSystem.newInstance(new URI("hdfs://hadoop01:9000"),conf);
 System.out.println(fs.toString());
}

第四种方式

@Test
public void getFileSystem4() throws  Exception{
    Configuration conf = new Configuration();
    conf.set("fs.defaultFS","hdfs:///hadoop01:9000");
    FileSystem fs = FileSystem.newInstance(conf);
    System.out.println(fs.toString());
}

2.创建目录

* HDFS的API操作的一般流程:

  • 1.获取一个客户端对象->之后可以set相关配置
  • 2.执行相关操作命令
  • 3.关闭资源
  • 4.该流程作用域:HDFS,Zookeeper,部分的Mapreduce
package com.normal.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
//创建目录
public class Mkdir {
    @Test
    public void mkdirTest() throws URISyntaxException, IOException, InterruptedException {
        //1.获取一个客户端对象
        //(1)加载Configuartion配置文件
        Configuration conf = new Configuration();
        //可以set一些配置参数 conf.set("dfs.replication","1"); 文件副本数为 1

       // 通过如下的方式去指定文件系统的类型,并且同时设置用户身份,获取客户端对象fs
       //(这就相当于建立连接了)
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop01:9000"),conf,"root");
        //2.执行相关操作
        fs.mkdirs(new Path("/IDEA-javatest/"));
        //3.关闭资源
        fs.close();
    }
}

运行成功后在50070页面打开文件管理界面如图:

HDFS portmap 自带的rpcbind功能 启动不了_apache_06

3.删除目录

package com.normal.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
//删除目录
public class Delete {
    @Test
    public void deleteTest() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();
        String user = "root";
        URI uri = new URI("hdfs://hadoop01:9000");
        FileSystem fs = FileSystem.get(uri,conf,user);
        //参数说明;参数1: 要删除的路径;参数2:是否递归删除
        fs.delete(new Path("/IDEA-javatest"),true);
        fs.close();
    }
}

4.上传文件(Windows->hdfs)

package com.normal.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class CopyFromLocal {
    @Test
    public void copyFromLocalTest() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();
        String user = "root";
        URI uri = new URI("hdfs://hadoop01:9000");
        FileSystem fs = FileSystem.get(uri,conf,user);
       // 参数1: 是否删除原数据;参数2:是否允许覆盖;参数三:原数据路径;参数四:目的路径
    Path p1 = new Path("F:\\C代码\\.vscode\\C实验\\链表.c");
    Path p2 = new Path("/IDEA-test/");
        fs.copyFromLocalFile(false, false, p1,p2);
        fs.close();
    }
}

5.参数的优先级

(比如我客户端代码中有xml配置文件,服务器中也有相同的xml配置文件,那么,客户端代码执行时以谁为准呢?)

优先级:(服务器默认配置)hdfs-default.xml < (服务器自定义配置)hdfs-site.xml < 在项目资源resource目录(classpath)下的配置文件 < 客户端在代码Configuration中set的配置

HDFS portmap 自带的rpcbind功能 启动不了_apache_07


上传的文件副本数为3。

(1)在resource中添加配置文件hdfs-site.xml
<?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>

再次上传查看文件副本数:

HDFS portmap 自带的rpcbind功能 启动不了_hdfs_08

(2)代码中添加配置

部分代码:

public void copyFromLocalTest() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();
        conf.set("dfs.replication", "2");//副本数配置
        String user = "root";
        URI uri = new URI("hdfs://hadoop01:9000");
        FileSystem fs = FileSystem.get(uri,conf,user);
       // 参数1: 是否删除原数据;参数2:是否允许覆盖;参数三:原数据路径;参数四:目的路径
        Path p1 = new Path("F:\\C代码\\.vscode\\C实验\\链表.c");
        Path p2 = new Path("/IDEA-test/链表03.c");
        fs.copyFromLocalFile(false, false, p1,p2);
        fs.close();
    }

HDFS portmap 自带的rpcbind功能 启动不了_apache_09

6.文件下载(hdfs->Windows)

// 参数1: 元文件是否删除;
//参数2:原数据路径;
//参数3:目的路径;
//参数4.是否开启本地路径校验
Path p1 = new Path("/IDEA-test/链表.c");
Path p2 = new Path("D://链表.c");
fs.copyToLocalFile(false, p1, p2, false);

7.获取文件详情

public void getListFile() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf =new Configuration();
        URI uri = new URI("hdfs://hadoop01:9000");
        String user = "root";
        FileSystem fs = FileSystem.get(uri,conf,user);
        //参数1:需要查看的文件路径; 参数2:是否递归
        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
        //RemoteIterator远程迭代器
        while (listFiles.hasNext()) {  //只要listFiles的下一个不为空就一直循环
            LocatedFileStatus fileStatus = listFiles.next();
            System.out.print("文件路径:"+fileStatus.getPath()+"\t");
            System.out.print("文件名:"+fileStatus.getPath().getName()+"\t");
            System.out.print("文件的用户:"+fileStatus.getOwner()+"\t");
            System.out.println("文件的权限:"+fileStatus.getPermission()+"\t");
        }
    }

8.判断是不是文件

public void IsFileTest() throws URISyntaxException, IOException, InterruptedException {
        Configuration conf = new Configuration();
        URI uri = new URI("hdfs://hadoop01:9000");
        String user ="root";
        FileSystem fs = FileSystem.get(uri,conf,user);
        FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
        for(FileStatus file:fileStatuses){
            if(file.isFile()){
                System.out.println(file.getPath().getName()+" 这个是文件");
            }
            else{
                System.out.println(file.getPath().getName()+"这个是文件夹");
            }
        }
    }