1 Maven工程配置
1 . 自定义组名和项目名称
2 . POM.xml
文件添加以下内容
<dependencies>
<!-- 测试模块 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.2</version>
</dependency>
<!-- log4j 新版本依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.0-alpha5</version>
</dependency>
</dependencies>
3 . 在src/main/resource
下边创建log4j2.xml
文件并添加以下内容
<?xml version="1.0" encoding="UTF-8"?>
<!--
status : 这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,会看到log4j2内部各种详细输出
monitorInterval : Log4j能够自动检测修改配置文件和重新配置本身, 设置间隔秒数。
-->
<Configuration status="WARN" monitorInterval="600">
<Properties>
<!-- 配置日志文件输出目录 -->
<Property name="LOG_HOME">${sys:catalina.home}/WebAppLogs/</Property>
</Properties>
<Appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<!-- <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="ACCEPT"/>
<!-- 输出日志的格式 -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!-- 设置日志格式并配置日志压缩格式(service.log.年份.gz) -->
<RollingRandomAccessFile name="service_appender"
fileName="${LOG_HOME}/service.log"
filePattern="${LOG_HOME}/service.log.%d{yyyy-MM-dd}.log.gz">
<!--
%d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间
%p : 日志输出格式
%c : logger的名称
%m : 日志内容,即 logger.info("message")
%n : 换行符
%C : Java类名
%L : 日志输出所在行数
%M : 日志输出所在方法名
hostName : 本地机器名
hostAddress : 本地ip地址
-->
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M -- %msg%xEx%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
<!-- <TimeBasedTriggeringPolicy interval="1" modulate="true" /> -->
</Policies>
</RollingRandomAccessFile>
<!-- DEBUG日志格式 -->
<RollingRandomAccessFile name="service_debug_appender"
fileName="${LOG_HOME}/service.log"
filePattern="${LOG_HOME}/service.log.%d{yyyy-MM-dd}.debug.gz">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M -- %msg%xEx%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<!-- 配置日志的根节点 -->
<root level="error">
<appender-ref ref="Console"/>
<appender-ref ref="service_appender" level="error"/>
</root>
<!-- 第三方日志系统 -->
<logger name="org.springframework.core" level="info"/>
<logger name="org.springframework.beans" level="info"/>
<logger name="org.springframework.context" level="info"/>
<logger name="org.springframework.web" level="info"/>
<logger name="org.jboss.netty" level="warn"/>
<logger name="org.apache.http" level="warn"/>
<!-- 日志实例(info),其中'service-log'继承root,但是root将日志输出控制台,而'service-log'将日志输出到文件,通过属性'additivity="false"'将'service-log'的
的日志不再输出到控制台 -->
<logger name="service_info_log" level="info" includeLocation="true" additivity="true">
<appender-ref ref="service_appender"/>
</logger>
<!-- 日志实例(debug) -->
<logger name="service_debug_log" level="debug" includeLocation="true" additivity="true">
<appender-ref ref="service_debug_appender"/>
</logger>
</Loggers>
</Configuration>
4 . 在src/main/resource
下创建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
2 Maven工程测试
1 . 创建对应的测试类
2 . 测试内容如下
package com.cxj.hadoop;
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;
public class hdfs {
@Test
public void testHdfs() throws IOException, InterruptedException {
URI uri = URI.create("hdfs://192.168.153.131:8020");
Configuration conf = new Configuration();
String user = "cxj";
// 创建文件系统
FileSystem fs = FileSystem.get(uri, conf, user);
boolean ismake = fs.mkdirs(new Path("/input"));
fs.close();
}
}
1 . 配置的
URI
是在core-site.xml
文件中配置的
2 . 用户看个人配置
3 . 通过命令hadoop fs -l
或者通过web
端管理页面,我这里是hadoop102:9870
,就可以看到刚才创建的目录
3 HDFS客户端操作
3.1 准备
package com.cxj.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
public class hdfs {
private URI uri ;
private Configuration conf ;
private String user ;
private FileSystem fs ;
// 测试实例运行前执行
@Before
public void init() throws IOException, InterruptedException {
uri = URI.create("hdfs://192.168.153.131:8020");
conf = new Configuration();
user = "cxj";
fs = FileSystem.get(uri, conf, user);
}
// 测试实例运行后执行
@After
public void after() throws IOException {
fs.close();
}
@Test
public void testHdfs() throws IOException, InterruptedException {
// 以下在这里边写具体的代码
}
}
3.1 HDFS文件上传
3.1.1 copyFromLocalFile
// delSrc:是否删除源文件,设置为true相当于剪切
// overwrite:是否重写
// src:本地的源
// dst:hdfs上存储的路径
public void copyFromLocalFile(boolean delSrc, boolean overwrite,
Path src, Path dst)
throws IOException {
Configuration conf = getConf();
FileUtil.copy(getLocal(conf), src, this, dst, delSrc, overwrite, conf);
}
// 例子
fs.copyFromLocalFile(false, true,
new Path("C:\\Users\\cxj\\Desktop\\test.txt"),
new Path("/input"));
3.1.2 临时配置文件配置
临时hdfs
配置,本次实例主要是操作已经配置好在虚拟机上的hadoop环境,他的默认配置文件以及自定义的配置文件都是在虚拟机上。但是有时候我们需要在客户端进行操作的时候需要临时配置一下选项,但是改动虚拟机上的配置文件比较麻烦或者不符合我们的有需求
1. 通过临时配置文件
基于上述要求,可以在src/main/resource
目录下创建配置文件。例如需要临时配置副本数为1,则直接在该路径下添加hdfs.-site.xml
文件并添加一下配置信息
<?xml version="1.0" encoding="UTF-8"?>
<?xm1-stylesheet type="text/xsl" href="configuration.xs1"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
2. 通过Conguration对象设置
除了在xml
文件配置临时配置以外,还可以通过Conguration
对象进行更改
3.1.3 配置文件优先级
通过
Conguration
对象配置 > 客户端配置文件配置 > 服务器上自定义配置文件(例如hdfs-site.xml
)> 默认配置文件(例如:hdfs-default.xml
)
3.2 HDFS文件下载
3.2.1 copyToLocalFile
// delSrc:是否删除源文件
// src:hdfs上的文件源
// dst:本地目录位置
// useRawLocalFileSystem:是否开启校验,为false会进行文件校验
// 保证文件的完整性,但是本地会出现校验文件,后缀为.crc
public void copyToLocalFile(boolean delSrc, Path src, Path dst,
boolean useRawLocalFileSystem) throws IOException {
Configuration conf = getConf();
FileSystem local = null;
if (useRawLocalFileSystem) {
local = getLocal(conf).getRawFileSystem();
} else {
local = getLocal(conf);
}
FileUtil.copy(this, src, local, dst, delSrc, conf);
}
//例子
fs.copyToLocalFile(false,
new Path("/input/test.txt"),
new Path("C:\\Users\\cxj\\Desktop"), false);
3.3 HDFS文件夹删除与创建
3.3.1 文件夹创建
// f:创建的文件夹的具体路径
public boolean mkdirs(Path f) throws IOException {
return mkdirs(f, FsPermission.getDirDefault());
}
// 例子
fs.mkdirs(new Path("/wcinput"));
相当于
Shell
操作的mkdir -p
3.3.2 文件夹删除delete
// f:删除的文件具体路径
// recursive:是否递归删除。非递归删只能删除文件或者空目录
public abstract boolean delete(Path f, boolean recursive)
throws IOException;
// 例子
fs.delete(new Path("/input"), true);
上述方式直接将文件删除,不会把删除的文件丢到回收站中。如果想将文件添加到回收站中,那么需要使用到
Trash
对象。使用如下代码,其中fs
是文件系统对象
并在resources
文件添加core-site.xml
文件并添加如下配置
<?xml version="1.0" encoding="UTF-8"?>
<?xm1-stylesheet type="text/xsl" href="configuration.xs1"?>
<configuration>
<property>
<name>fs.trash.interval</name>
<value>1</value>
</property>
<property>
<name>fs.trash.checkpoint.interval</name>
<value>1</value>
</property>
</configuration>
或者直接使用Confguration对象
进行配置
conf.set("fs.trash.interval", 1)
conf.set("fs.trash.checkpoint.interval", 1)
3.4 HDFS文件名更改/移动
3.4.1 rename
可以做
文件移动
,也可以用做文件名更改
// src:HDFS上文件的原来地址
// dst:更改后的目的地址
public abstract boolean rename(Path src, Path dst)
throws IOException;
// 文件名更改
fs.rename(new Path("/input/test.txt"), new Path("/input/a.txt"));
// 文件移动
fs.rename(new Path("/input/a.txt"), new Path("/wcinput"));
// 移动且更名
fs.rename(new Path("/input/test.txt"), new Path("/wcinput/a.txt"));
3.5 HDFS详情查看
3.5.1 listFiles
// f:路径
// recursive:是否递归。设置true递归,就会遍历其下的子目录下的文件
public RemoteIterator<LocatedFileStatus> listFiles(
final Path f, final boolean recursive)
// 例子
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/input"), 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.getReplication());System.out.println("文件块大小:"+ fileStatus.getBlockSize());
System.out.println("文件块位置:" + Arrays.toString(fileStatus.getBlockLocations()));
}
块信息:
文件块位置:[0,1,hadoop104,hadoop102]
。这里是根据文件大小和设置的块大小进行分块,0,1
表示开始位置和结束位置,因为上传的文件就是1kb
,所以就是一块,副本存储在hadoop104
和hadoop102
上
3.6 HDFS文件和文件夹判断
// f:路径
public abstract FileStatus[] listStatus(Path f)
throws FileNotFoundException,IOException;
// 例子
FileStatus[] status = fs.listStatus(new Path("/"));
for(FileStatus s: status){
// 文件夹
if(s.isDirectory()){
System.out.println(s.getPath());
}else if(s.isFile()){
System.out.println(s.getPath());
}
}
4 文件流扩展
4.1 文件上传
FileInputStream fis = new FileInputStream(new File("C:\\Users\\cxj\\Desktop\\test.txt"));
// 输出的需要指定输出的文件名,文件可以不存在
// 而使用输出的copyFromLocalFile是不需要指定到具体的上传的目录
// 只需要指定上传到哪个目录就可以了
FSDataOutputStream fos = fs.create(new Path("/wcinput/b.txt"));
// 输入流通过输出流输入到目的地
IOUtils.copyBytes(fis, fos ,conf);
// 关闭轮流
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);
4.2 文件下载
FSDataInputStream fos = fs.open(new Path("/wcinput/b.txt"));
FileOutputStream fis = new FileOutputStream(new File("C:\\Users\\cxj\\Desktop\\b.txt"));
IOUtils.copyBytes(fos, fis, conf);
IOUtils.closeStream(fis);
IOUtils.closeStream(fos);