文章目录
- 一.实验环境准备
- 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.判断是不是文件
一.实验环境准备
1.在windows环境当中安装hadoop bin,maven,配置HADOOP_HOME,MVN_HOME,Path环境变量。
变量值为安装目录(安装目录尽量不含中文和空格)
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
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(找不到就搜索)
5.建立子项目
在Project下的Hadoop右击new一个Module,父项目为Hadoop。
(新项目的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页面打开文件管理界面如图:
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的配置
上传的文件副本数为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>
再次上传查看文件副本数:
(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();
}
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()+"这个是文件夹");
}
}
}