分布式文件系统HDFS Shell命令和API编程
实验实现过程
重要知识点:
- Hadoop分布式文件系统(Hadoop Distributed File System,HDFS)是Hadoop核心组件之一,如果已经安装了Hadoop,其中就已经包含了HDFS组件,不需要另外安装。
- 利用Shell命令与HDFS进行交互
Hadoop支持很多Shell命令,其中fs是HDFS最常用的命令,利用fs可以查看HDFS文件系统的目录结构、上传和下载数据、创建文件等。
注意
命令是以”./bin/hadoop dfs”开头的Shell命令方式,实际上有三种shell命令方式。
1) hadoop fs
2) hadoop dfs(已过期)
3) hdfs dfs(常用)
hadoop fs适用于任何不同的文件系统,比如本地文件系统和HDFS文件系统
hadoop dfs只能适用于HDFS文件系统
hdfs dfs跟hadoop dfs的命令作用一样,也只能适用于HDFS文件系统
3.常用Shell命令解析
hdfs dfs -appendToFile <localsrc> ... <dst>
可同时上传多个文件到HDFS里面
hdfs dfs -cat URI [URI ...]
查看文件内容
hdfs dfs -chgrp [-R] GROUP URI [URI ...]
修改文件所属组
hdfs dfs -chmod [-R] <MODE[,MODE]... | OCTALMODE> URI [URI ...]
修改文件权限
hdfs dfs -chown [-R] [OWNER][:[GROUP]] URI [URI ]
修改文件所有者,文件所属组,其他用户的读、写、执行权限
hdfs dfs -copyFromLocal <localsrc> URI
复制文件到hdfs
hdfs dfs -copyToLocal [-ignorecrc] [-crc] URI <localdst>
复制文件到本地
hdfs dfs -count [-q] <paths>
统计文件及文件夹数目
hdfs dfs -cp [-f] URI [URI ...] <dest>
Hadoop HDFS 文件系统间的文件复制
hdfs dfs -du [-s] [-h] URI [URI ...]
统计目录下的文件及大小
hdfs dfs -dus <args>
汇总目录下的文件总大小
hdfs dfs -get [-ignorecrc] [-crc] <src> <localdst>
下载文件到本地
hdfs dfs -getmerge <src> <localdst> [addnl]
合并下载文件到本地
hdfs dfs -ls <args>
查看目录
hdfs dfs -ls -R <args>
循环列出目录、子目录及文件信息
hdfs dfs -mkdir [-p] <paths>
创建空白文件夹
dfs -moveFromLocal <localsrc> <dst>
剪切文件到hdfs
hdfs dfs -moveToLocal [-crc] <src> <dst>
剪切文件到本地
hdfs dfs -mv URI [URI ...] <dest>
剪切hdfs文件
hdfs dfs -put <localsrc> ... <dst>
上传文件
hdfs dfs -rm [-skipTrash] URI [URI ...]
删除文件/空白文件夹
hdfs dfs -rm -r [-skipTrash] URI [URI ...]
递归删除 删除文件及文件夹下的所有文件
hdfs dfs -setrep [-R] [-w] <numReplicas> <path>
修改副本数
hdfs dfs -stat URI [URI ...]
显示文件统计信息
hdfs dfs -tail [-f] URI
查看文件尾部信息
hdfs dfs -test -[ezd] URI
对PATH进行如下类型的检查:
-e PATH是否存在,如果PATH存在,返回0,否则返回1
-z 文件是否为空,如果长度为0,返回0,否则返回1
-d 是否为目录,如果PATH为目录,返回0,否则返回1
hdfs dfs -text <src>
查看文件内容
hdfs dfs -touchz URI [URI ..
.]
创建长度为0的空文件
实验内容与步骤:
- 配置hadoop的环境变量:
首先,hadoop shell命令在/bigdata/hadoop-3.1.1/bin目录下,编辑/etc/profile配置文件,增加如下内容:
sudo vi /etc/profile
export JAVA_HOME=/opt/java/jdk1.8.0_181
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
export HADOOP_HOME=/bigdata/hadoop-3.1.1
重新读取:
source /etc/profile
- 命令查看方式:
我们可以在终端输入如下命令,查看dfs总共支持了哪些命令:
hdfs dfs
在终端输入如下命令,可以查看具体某个命令的作用
例如:我们查看put命令如何使用,可以输入如下命令:
实验内容与步骤:
- 利用Hadoop提供的Shell命令完成以下指定功能,并编程实现相同任务:
注:请首先练习HDFS shell命令的使用,比如创建文件、文件夹、删除文件、文件夹,上传文件,下载文件,追加文件等常用功能,然后课后完成Java的实现。
(1) 提供一个HDFS的目录的路径,对该目录进行创建和删除操作。创建目录时,如果目录文件所在目录不存在则自动创建相应目录;删除目录时,由用户指定当该目录不为空时是否还删除该目录;
Shell命令实现:
• 创建目录
hdfs dfs -mkdir -p /dir1/dir2
• 删除目录(如果目录非空则会提示not empty,不执行删除)
hdfs dfs -rmdir /dir1/dir2
目录为空时:
• 强制删除目录
hdfs dfs -rm -r /dir1/dir2
是否创建成功可以通过浏览器查看
Java实现:
import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import java.io.*;public class HdfsApi {
/**
* 判断路径是否存在
*/
public static boolean test(Configuration conf, String path) throws IOException {
FileSystem fs = FileSystem.get(conf);
return fs.exists(new Path(path));
}
/**
* 判断目录是否为空
* true: 空,false: 非空
*/
public static boolean isDirEmpty(Configuration conf, String remoteDir) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path dirPath = new Path(remoteDir);
RemoteIterator<LocatedFileStatus> remoteIterator = fs.listFiles(dirPath, true);
return !remoteIterator.hasNext();
}
/**
* 创建目录
*/
public static boolean mkdir(Configuration conf, String remoteDir) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path dirPath = new Path(remoteDir);
boolean result = fs.mkdirs(dirPath);
fs.close();
return result;
}
/**
* 删除目录
*/
public static boolean rmDir(Configuration conf, String remoteDir) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path dirPath = new Path(remoteDir);
/* 第二个参数表示是否递归删除所有文件 */
boolean result = fs.delete(dirPath, true);
fs.close();
return result;
}
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
conf.set("fs.default.name","hdfs://localhost:9000");
String remoteDir = "/user/hadoop/input"; // HDFS目录
Boolean forceDelete = false; // 是否强制删除
try {
/* 判断目录是否存在,不存在则创建,存在则删除 */
if ( !HdfsApi.test(conf, remoteDir) ) {
HdfsApi.mkdir(conf, remoteDir); // 创建目录
System.out.println("创建目录: " + remoteDir);
} else {
if ( HdfsApi.isDirEmpty(conf, remoteDir) || forceDelete ) { // 目录为空或强制删除
HdfsApi.rmDir(conf, remoteDir);
System.out.println("删除目录: " + remoteDir);
} else { // 目录不为空
System.out.println("目录不为空,不删除: " + remoteDir);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2) 向HDFS中指定的文件追加内容,由用户指定内容追加到原有文件的开头或结尾;
Shell命令实现:
• 追加到文件末尾
hdfs dfs -appendToFile local.txt text.txt
• 追加到文件开头
hdfs dfs -copyFromLocal -f local.txt /desText.txt
Java实现:
import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import java.io.*;public class HdfsApi {
/**
* 判断路径是否存在
*/
public static boolean test(Configuration conf, String path) throws IOException {
FileSystem fs = FileSystem.get(conf);
return fs.exists(new Path(path));
}
/**
* 追加文本内容
*/
public static void appendContentToFile(Configuration conf, String content, String remoteFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path remotePath = new Path(remoteFilePath);
/* 创建一个文件输出流,输出的内容将追加到文件末尾 */
FSDataOutputStream out = fs.append(remotePath);
out.write(content.getBytes());
out.close();
fs.close();
}
/**
* 追加文件内容
*/
public static void appendToFile(Configuration conf, String localFilePath, String remoteFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path remotePath = new Path(remoteFilePath);
/* 创建一个文件读入流 */
FileInputStream in = new FileInputStream(localFilePath);
/* 创建一个文件输出流,输出的内容将追加到文件末尾 */
FSDataOutputStream out = fs.append(remotePath);
/* 读写文件内容 */
byte[] data = new byte[1024];
int read = -1;
while ( (read = in.read(data)) > 0 ) {
out.write(data, 0, read);
}
out.close();
in.close();
fs.close();
}
/**
* 移动文件到本地
* 移动后,删除源文件
*/
public static void moveToLocalFile(Configuration conf, String remoteFilePath, String localFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path remotePath = new Path(remoteFilePath);
Path localPath = new Path(localFilePath);
fs.moveToLocalFile(remotePath, localPath);
}
/**
* 创建文件
*/
public static void touchz(Configuration conf, String remoteFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path remotePath = new Path(remoteFilePath);
FSDataOutputStream outputStream = fs.create(remotePath);
outputStream.close();
fs.close();
}
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS文件
String content = "新追加的内容\n";
String choice = "after"; //追加到文件末尾//
String choice = "before"; // 追加到文件开头
try {
/* 判断文件是否存在 */
if ( !HdfsApi.test(conf, remoteFilePath) ) {
System.out.println("文件不存在: " + remoteFilePath);
} else {
if ( choice.equals("after") ) { // 追加在文件末尾
HdfsApi.appendContentToFile(conf, content, remoteFilePath);
System.out.println("已追加内容到文件末尾" + remoteFilePath);
} else if ( choice.equals("before") ) { // 追加到文件开头
/* 没有相应的api可以直接操作,因此先把文件移动到本地,创建一个新的HDFS,再按顺序追加内容 */
String localTmpPath = "/user/hadoop/tmp.txt";
HdfsApi.moveToLocalFile(conf, remoteFilePath, localTmpPath); // 移动到本地
HdfsApi.touchz(conf, remoteFilePath); // 创建一个新文件
HdfsApi.appendContentToFile(conf, content, remoteFilePath); // 先写入新内容
HdfsApi.appendToFile(conf, localTmpPath, remoteFilePath); // 再写入原来内容
System.out.println("已追加内容到文件开头: " + remoteFilePath);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(3) 删除HDFS中指定的文件;
Shell命令实现:
hdfs dfs -rm text.txt
Java实现:
import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import java.io.*;public class HdfsApi {
/**
* 删除文件
*/
public static boolean rm(Configuration conf, String remoteFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path remotePath = new Path(remoteFilePath);
boolean result = fs.delete(remotePath, false);
fs.close();
return result;
}
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS文件
try {
if ( HdfsApi.rm(conf, remoteFilePath) ) {
System.out.println("文件删除: " + remoteFilePath);
} else {
System.out.println("操作失败(文件不存在或删除失败)");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(4) 删除HDFS中指定的目录,由用户指定目录中如果存在文件时是否删除目录;
Shell命令实现:
• 删除目录(如果目录非空则会提示not empty,不执行删除)
hdfs dfs -rmdir dir1/dir2
• 强制删除目录
hdfs dfs -rm -R /dir1/dir2
Java实现:
import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import java.io.*;public class HdfsApi {
/**
* 判断目录是否为空
* true: 空,false: 非空
*/
public static boolean isDirEmpty(Configuration conf, String remoteDir) throws IOException {FileSystem fs = FileSystem.get(conf);
Path dirPath = new Path(remoteDir);
RemoteIterator<LocatedFileStatus> remoteIterator = fs.listFiles(dirPath, true);
return !remoteIterator.hasNext();
}
/**
* 删除目录
*/
public static boolean rmDir(Configuration conf, String remoteDir, boolean recursive) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path dirPath = new Path(remoteDir);
/* 第二个参数表示是否递归删除所有文件 */
boolean result = fs.delete(dirPath, recursive);
fs.close();
return result;
}
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
conf.set("fs.default.name","hdfs://localhost:9000");
String remoteDir = "/user/hadoop/dir1/dir2"; // HDFS目录
Boolean forceDelete = false; // 是否强制删除
try {
if ( !HdfsApi.isDirEmpty(conf, remoteDir) && !forceDelete ) {
System.out.println("目录不为空,不删除");
} else {
if ( HdfsApi.rmDir(conf, remoteDir, forceDelete) ) {
System.out.println("目录已删除: " + remoteDir);
} else {
System.out.println("操作失败");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5) 在HDFS中,将文件从源路径移动到目的路径。
Shell命令实现:
hdfs dfs -mv /desText.txt /dir1
Java实现:
import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import java.io.*;public class HdfsApi {
/**
* 移动文件
*/
public static boolean mv(Configuration conf, String remoteFilePath, String remoteToFilePath) throws IOException {
FileSystem fs = FileSystem.get(conf);
Path srcPath = new Path(remoteFilePath);
Path dstPath = new Path(remoteToFilePath);
boolean result = fs.rename(srcPath, dstPath);
fs.close();
return result;
}
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "hdfs:///user/hadoop/text.txt"; // 源文件HDFS路径
String remoteToFilePath = "hdfs:///user/hadoop/input"; // 目的HDFS路径
try {
if ( HdfsApi.mv(conf, remoteFilePath, remoteToFilePath) ) {
System.out.println("将文件 " + remoteFilePath + " 移动到 " + remoteToFilePath);
} else {
System.out.println("操作失败(源文件不存在或移动失败)");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}