本文介绍Linux OS中关于HDFS文件操作的常用Shell命令,利用Web界面查看和管理Hadoop文件系统,以及利用Hadoop提供的 Java API进行基本的文件操作。
文章目录
让我们开始吧!启动Hadoop~
cd /usr/local/hadoop #到Hadoop安装目录
./sbin/start-dfs.sh #启动hadoop
一、利用shell命令和HDFS进行交互
- 三种shell命令方式:
- hadoop fs
适用于任何不同的文件系统,比如本地文件系统和HDFS文件系统。 - hadoop dfs
只能适用于HDFS文件系统 - hdfs dfs
同上,只能适用于HDFS系统
- 查看fs总共支持了哪些命令
./bin/hadoop fs
- 查看具体某个命令的作用
./bin/hadoop fs -help put # 以查看put命令如何使用为例
1.目录操作
hadoop系统安装后,第一次使用HDFS时,需要先在HDFS中创建用户目录。
而本博客中采用Hadoop用户登录Linux系统,因此,需要在HDFS中为hadoop用户创建一个用户目录。
cd /usr/local/hadoop # 设置当前目录
./bin/hdfs dfs -mkdir -p /user/hadoop
其中:
-mkdir
是创建目录-p
表示若是多级目录,则父目录和子目录一起创建。本例中"/user/hadoop"就是一个多级目录,所以必须要使用参数-p
(否则会出错)- “/** ”表示绝对目录,“* *”表示相对目录
- ~ 代表是home目录,也就是家目录, / 代表的是根目录
"/user/hadoop"目录成为hadoop用户对应的用户目录。显示HDFS中与当前hadoop对应的用户目录下的内容
./bin/hdfs dfs -ls .
其中:
-ls
表示列出HDFS某个目录下的所有内容.
表示HDFS中的当前用户目录,即"/user/hadoop"目录。因此,命令也等价于
./bin/hdfs dfs -ls /user/hadoop
列出HDFS上的所有目录
./bin/hdfs dfs -ls
创建一个input目录
./bin/hdfs dfs -mkdir input
在创建input目录时,采用了相对路径形式。actually,这个input目录创建成功后,在HDFS中的完整路径是"/user/hadoop/input"。若在HDFS的根目录下创建一个名称为input的目录,需要使用如下命名
./bin/hdfs dfs -mkdir /input
使用rm
命令删除一个目录,比如,可以使用如下命令删除刚才在HDFS中创建的"/input"目录(不是"/user/hadoop/input"目录)
./bin/hdfs dfs -rm -r /inout
其中:
-r
参数表示删除"/input"目录及其子目录下的所有内容。若删除的一个目录包含了子目录,则必须使用“-r”参数,否则会执行失败(可以类比数据库中的级联cascade和限制restrict)
2.文件操作
在实际应用中,经常需要从本地文件系统向HDFS中上传文件 或 把HDFS中的文件下载到本地文件系统中。
本地上传到HDFS(-put)
firstly,使用vim编辑器,在本地Linux文件系统的"/home/hadoop"目录下创建一个文件myLocalFile.txt,输入任意单词做内容。例如
harder
stronger
freer
把本地文件系统的"/home/hadoop/myLocalFile.txt"上传到HDFS中的当前用户目录的input目录下,即上传到HDFS的"/user/hadoop/input/"目录下
./bin/hdfs dfs -put /home/hadoop/myLocalFile.txt input # Ubuntu中不以后缀名区分文件,仅供用户辨别这是个文本文件而非目录啥的
使用-ls
命令查看文件是否成功上传到HDFS
./bin/hdfs dfs -ls input
查看HDFS中的myLocalFile.txt文件中的内容
./bin/hdfs dfs -cat input/myLocalFile.txt
HDFS中下载到本地(-get)
把HDFS中的myLocalFile.txt文件下载到本地文件系统中的"/home/hadoop/下载/"中
./bin/hdfs dfs -get input/myLocalFile.txt /home/hadoop/下载
到本地文件系统查看下载下来的文件myLocalFile.txt
cd ~
cd 下载
ls
cat myLocalFile.txt
HDFS不同目录间的拷贝(-cp)
关于把文件从HDFS中的一个目录拷贝到HDFS中的另外一个目录。比如,若把HDFS的"/user/hadoop/input/myLocalFile.txt"文件,拷贝到HDFS的另外一个目录"/input"中(这个input目录位于HDFS根目录下)
./bin/hdfs dfs -cp input/myLocalFile.txt /input
二、利用Web界面管理HDFS
打开Linux自带的Firefox浏览器,输入localhost:9870
即可看到HDFS的web管理界面
三、利用Java API和HDFS进行交互
Hadoop API文档
Hadoop采用Java语言开发,提供了Java API和HDFS进行交互。Hadoop不同的文件系统之间通过调用Java API进行交互,上文介绍的shell命令,本质上是Java API的应用。利用Java API进行交互,需要利用软件Eclipse编写Java程序。
1.在Ubuntu中安装Eclipse
eclipse官网
下载后可通过FileZilla或者其他方法传到linux系统中。以存在"~/Downloads"下,为例。
- 解压缩
cd ~/Downloads
sudo tar -zxvf ./eclipse-4.7.0-Linux.gtk.x86_64.tar.gz -C /usr/local
把Downloads目录下的这个eclipse解压到C盘的"/usr/local"中
- 启动eclipse
cd /usr/local/eclipse
./eclipse # 而后出现蓝色开启界面
2.使用eclipse开发调试HDFS Java程序
为了提高程序编写和调试效率,本教程采用eclipse工具编写Java程序。
本次小实践任务:
若在目录"hdfs://localhost:9000/user/hadoop"下有文件file1.txt,file2.txt,file3.txt,file4.abc和file5.abc。
需要从该目录中过滤出所有后缀名不为“.abc”的文件,对过滤之后的文件进行读取,并将这些文件的内容合并到文件"hdfs://localhost:9000/user/hadoop/merge.txt"中
(1)在eclipse中创建项目
启动eclipse后,提示设置工作空间workspace。可以直接选择默认设置“/home/hadoop/workspace”,点击ok
。
file→New→选择Java Project→finsh.
输入工程名→JRE选择之前安装的JDK
→next
(2)为项目添加需要的JAR包
Libraries→Add External JARS导入外部jar包
选择需要的jar包(注意是jar包,不要带上目录下的其他文件夹)→🆗
需要添加的jar包有:
- “/usr/local/hadoop/share/hadoop/common”目录下的所有jar包(四个)
- “/usr/local/hadoop/share/hadoop/common/lib”目录下的所有jar包
- “/usr/local/hadoop/share/hadoop/hdfs”目录下的所有jar包
- “/usr/local/hadoop/share/hadoop/hdfs/lib”目录下的所有jar包
全部添加后,点击finish.
弹出的界面中选择Open Perspective打开视图
(3)编写Java应用程序
eclipse工作界面左侧的"package explorer"面板中,右键点击刚才建好的工程名称“HDFSExample”→New→Class
类名为MergeFile,其他采用默认设置即可。MergeFile.java中的代码内容:
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
/**
* 过滤掉文件名满足特定条件的文件
*/
class MyPathFilter implements PathFilter {
String reg = null;
MyPathFilter(String reg) {
this.reg = reg;
}
public boolean accept(Path path) {
if (!(path.toString().matches(reg)))
return true;
return false;
}
}
/***
* 利用FSDataOutputStream和FSDataInputStream合并HDFS中的文件
*/
public class MergeFile {
Path inputPath = null; //待合并的文件所在的目录的路径
Path outputPath = null; //输出文件的路径
public MergeFile(String input, String output) {
this.inputPath = new Path(input);
this.outputPath = new Path(output);
}
public void doMerge() throws IOException {
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fsSource = FileSystem.get(URI.create(inputPath.toString()), conf);
FileSystem fsDst = FileSystem.get(URI.create(outputPath.toString()), conf);
//下面过滤掉输入目录中后缀为.abc的文件
FileStatus[] sourceStatus = fsSource.listStatus(inputPath,
new MyPathFilter(".*\\.abc"));
FSDataOutputStream fsdos = fsDst.create(outputPath);
PrintStream ps = new PrintStream(System.out);
//下面分别读取过滤之后的每个文件的内容,并输出到同一个文件中
for (FileStatus sta : sourceStatus) {
//下面打印后缀不为.abc的文件的路径、文件大小
System.out.print("路径:" + sta.getPath() + " 文件大小:" + sta.getLen()
+ " 权限:" + sta.getPermission() + " 内容:");
FSDataInputStream fsdis = fsSource.open(sta.getPath());
byte[] data = new byte[1024];
int read = -1;
while ((read = fsdis.read(data)) > 0) {
ps.write(data, 0, read);
fsdos.write(data, 0, read);
}
fsdis.close();
}
ps.close();
fsdos.close();
}
public static void main(String[] args) throws IOException {
MergeFile merge = new MergeFile(
"hdfs://localhost:9000/user/hadoop/",
"hdfs://localhost:9000/user/hadoop/merge.txt");
merge.doMerge();
}
}
(4)编译运行程序
注意:在Hadoop启动的基础上,再去编译运行程序
cd /usr/local/hadoop
./sbin/start-dfs.sh
在HDFS的“/user/hadoop”目录下创建五个文件。
先在本地创建五个文件
file1.txt的内容是: this is file1.txt
file2.txt的内容是: this is file2.txt
file3.txt的内容是: this is file3.txt
file4.abc的内容是: this is file4.abc
file5.abc的内容是: this is file5.abc
用put命令把本地文件上传到HDFS中
./bin/hdfs dfs -put ./file1.txt /user/hadoop # 以file1.txt为例
编译运行
控制台输出
在HDFS中查看生成的merge.txt文件
cd /usr/local/hadoop
./bin/hdfs dfs -ls /user/hadoop
./bin/hdfs dfs -cat /user/hadoop/merge.txt
(5)应用程序的部署
把Java应用程序生成jar包,部署到Hadoop平台上运行。
- 在Hadoop安装目录中新建一个名为myapp的目录,用来存放我们自己编写的hadoop应用程序
cd /usr/local/hadoop
mkdir myapp
- 在eclipse工作界面左边的“package explorer”面板中的工程名称"HDFSExample"上右键,选择"Export"导出⇨选择runnable JAR file⇨next
- “Launch configuration”:设置生成的jar包被部署启动时运行的主类。本例中在下拉列表中选择刚才配置的类"MergeFile-HDFSExample"。
“Export destination”:设置jar包要保存到哪个目录。本例中设置为“/usr/local/hadoop/myapp/HDFSExample.jar”,其中在myapp目录下对jar包起名为HDFSExample
“Library handling”选择“Extra required libraries into generated JAR”。
最后点击finish,然后无视之后的警告一路🆗即可。
- 上述已完成了HDFSExample工程打包生成的HDFSExample.jar文件。
在Linux系统中查看生成的HDFSExample.jar文件。
cd /usr/local/hadoop/myapp
ls
由于之前已经运行过一次程序并生成了merge.txt。因此,首先删除该文件
cd /usr/local/hadoop
./bin/hdfs dfs -rm /user/hadoop/merge/txt
在Linux系统中,使用hadoop jar命令运行程序
cd /usr/local/hadoop
./bin/hadoop jar ./myapp/HDFSExample.jar
再次执行完程序后,在HDFS中产看生成的merge.txt文件
cd /usr/local/hadoop
./bin/hdfs dfs -ls /user/hadoop
./bin/hdfs dfs -cat /user/hadoop/merge/txt
补充(练习代码文件)
- 写入文件
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.Path;
public class Chapter3 {
public static void main(String[] args) {
try {
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs = FileSystem.get(conf);
byte[] buff = "Hello world".getBytes(); // 要写入的内容
String filename = "test"; //要写入的文件名
FSDataOutputStream os = fs.create(new Path(filename));
os.write(buff,0,buff.length);
System.out.println("Create:"+ filename);
os.close();
fs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 判断文件存在
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class Chapter3 {
public static void main(String[] args) {
try {
String filename = "test";
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs = FileSystem.get(conf);
if(fs.exists(new Path(filename))){
System.out.println("文件存在");
}else{
System.out.println("文件不存在");
}
fs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 读取文件
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FSDataInputStream;
public class Chapter3 {
public static void main(String[] args) {
try {
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs = FileSystem.get(conf);
Path file = new Path("test");
FSDataInputStream getIt = fs.open(file);
BufferedReader d = new BufferedReader(new InputStreamReader(getIt));
String content = d.readLine(); //读取文件一行
System.out.println(content);
d.close(); //关闭文件
fs.close(); //关闭hdfs
} catch (Exception e) {
e.printStackTrace();
}
}
}