HDFS操作
Posted 糟老头修炼记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDFS操作相关的知识,希望对你有一定的参考价值。
Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。
HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。
HDFS放宽了一部分POSIX约束,来实现流式读取文件系统数据的目的。
HDFS在最开始是作为Apache Nutch搜索引擎项目的基础架构而开发的。HDFS是Apache Hadoop Core项目的一部分。
HDFS有着高容错性(fault-tolerant)的特点,并且设计用来部署在低廉的(low-cost)硬件上。而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(largedata set)的应用程序。
HDFS放宽了(relax)POSIX的要求(requirements)这样可以实现流的形式访问(streaming access)文件系统中的数据。
1.登录Hadoop用户,启动Hadoop:
su hadoop #切换成hadoop用户,密码:hadoop
cd /usr/local/hadoop #进入hadoop目录
./sbin/start-dfs.sh #启动hadoop,中间遇到选择,输入"yes"
2.利用shell命令和Hadoop进行交互:
fs是HDFS常用的命令,利用fs可以查看HDFS文件系统的目录结构、上传和下载数据、创建文件等。
hadoop fs:适用于任何不同的文件系统,比如本地文件系统和HDFS文件系统
hadoop dfs:只能适用于HDFS文件系统
hdfs dfs:与hadoop dfs的命令作用一样,也只能适用于HDFS文件系统
(1)查看fs共支持了哪些命令:
./bin/hadoop fs
(2)查看具体某个命令的作用:查看put命令如何使用
./bin/hadoop fs -help put
(3)创建用户目录:
cd /usr/local/hadoop
./bin/hdfs dfs -mkdir -p /user/hadoop
该命令表示在HDFS中创建一个“/user/hadoop”目录,“-mkdir”是创建目录的操作,“-p”表示如果是多级目录,则父目录和子目录一起创建, “/user/hadoop”就是一个多级目录,因此必须使用参数“-p”,否则会出错。
“/user/hadoop”目录就成为hadoop用户对应的用户目录
(4)显示HDFS中与当前用户hadoop对应的用户目录下的内容:
./bin/hdfs dfs -ls .
“-ls”表示列出HDFS某个目录下的所有内容,“.”表示HDFS中的当前用户目录,也就是“/user/hadoop”目录,等价于:
./bin/hdfs dfs -ls /user/hadoop
(5)列出HDFS根目录上的所有目录:
./bin/hdfs dfs -ls /
(6)创建一个test目录和input目录:
./bin/hdfs dfs -mkdir test
在创建test目录时,采用了相对路径形式,实际上,这个test目录创建成功以后,它在HDFS中的完整路径是“/user/hadoop/test”
在HDFS的根目录下创建一个名称为input的目录:
./bin/hdfs dfs -mkdir /input
(7)删除一个目录:使用rm命令,
删除刚才在HDFS中/user/hadoop目录下创建的“test”目录:
./bin/hdfs dfs -rm -r test
“-r”参数表示如果删除“/user/hadoop/test”目录及其子目录下的所有内容,如果要删除的一个目录包含了子目录,则必须使用“-r”参数,否则会执行失败。
(8)创建文件:
在本地Linux文件系统的“/home/hadoop/”目录下创建一个文件myLocalFile.txt
cd /home/hadoop
vim myLocalFile.txt
随意输入一些单词然后保存:
hadoop
Spark
XMU BLAB
把本地文件系统的“/home/hadoop/myLocalFile.txt”上传到HDFS中的当前用户目录的input目录下,即上传到HDFS的“/user/hadoop/input/”目录下:
cd /usr/local/hadoop #进入hadoop目录,因为所有以./bin开头的命令都要在 /usr/local/hadoop路径下执行
./bin/hdfs dfs -put /home/hadoop/myLocalFile.txt input #复制文件
使用ls命令查看一下文件是否成功上传到HDFS中:
./bin/hdfs dfs -ls input
查看HDFS中的myLocalFile.txt这个文件的内容:
./bin/hdfs dfs -cat input/myLocalFile.txt
(9)下载文件:把HDFS中的myLocalFile.txt文件下载到本地文件系统中的“/home/hadoop/down/”这个目录下
在本地创建down目录:
cd /home/hadoop
mkdir down #创建本地目录
cd /usr/local/hadoop #注:所有以./bin开头的命令都要在 /usr/local/hadoop路径下执行
./bin/hdfs dfs -get input/myLocalFile.txt /home/hadoop/down
到本地文件系统查看下载下来的文件myLocalFile.txt:
cd /home/hadoop/down
ls
cat myLocalFile.txt
(10)复制:把HDFS的“/user/hadoop/input/myLocalFile.txt”文件,拷贝到HDFS的另外一个目录“/input”中:
cd /usr/local/hadoop #注:所有以./bin开头的命令都要在 /usr/local/hadoop路径下执行
./bin/hdfs dfs -mkdir /input #该目录如果已经删掉,则重新创建一下
./bin/hdfs dfs -cp input/myLocalFile.txt /input
(11)网址:http://localhost:50070,可看到HDFS的web管理界面:
3、利用Java API与HDFS进行交互
(1)在Ubuntu中安装eclipse
切换hadoop用户,启动Hadoop:
su hadoop #切换成hadoop用户
cd /usr/local/hadoop #进入hadoop目录
./sbin/start-dfs.sh #如果hadoop已经启动,则略过此命令;如未启动,则执行此命令,中间遇到选择,输入"yes"
将Eclipse安装在/usr/local/目录下:
cd /usr/local/
下载 Eclipse压缩包到当前目录(/usr/local/)下,对Eclipse解压缩:
sudo tar -zxf eclipse-jee-luna-SR2-linux-gtk-x86_64.tar.gz #hadoop用户密码是'hadoop'
sudo chown -R hadoop ./eclipse # 修改文件权限
(2).创建eclipse桌面快捷图标
cd /usr/share/applications
sudo vim eclipse.desktop #执行此命令时可能会让输入密码
将下列代码复制到eclipse.desktop文件里面:
[DesktopEntry]
Encoding=UTF-8
Name=Eclipse
Comment=Eclipse
Exec=/usr/local/eclipse/eclipse
Icon=/usr/local/eclipse/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;
“Exec=”后面为eclipse安装目录下的eclipse程序的位置路径
“Icon=”后面为eclipse安装目录下的图标图片的路径;
将其变为可执行文件:
sudo chmod u+x eclipse.desktop
找到/usr/share/applications目录,将Eclipse图标右键发送或复制到桌面即可:
(3)在eclipse里创建项目:
第一次打开Eclipse,默认工作空间目录位于“/root/workspace”下面,
选择“File->New->Other->Java Project”菜单,开始创建一个Java工程:
在“Project name”后面输入工程名称“HDFSExample”,选中“Use default location”,让这个Java工程的所有文件都保存到默认的“/root/workspace/HDFSExample”目录下即可。
在“JRE”这个选项卡中,可以选择当前的Linux系统中已经安装好的JDK,比如java-8-openjdk-amd64。然后,点击界面底部的“Next>”按钮,进入下一步的设置。
(4).为项目添加需要用到的JAR包
需要在这个界面中加载该Java工程所需要用到的JAR包,这些JAR包中包含了可以访问HDFS的Java API。这些JAR包都位于Linux系统的Hadoop安装目录下,就是在“/usr/local/hadoop/share/hadoop”目录下。
点击界面中的“Libraries”选项卡,然后,点击界面右侧的“Add External JARs…”按钮,界面如图:
在该窗口中,选择“FileSystem(文件系统)”,找到“/usr/local/hadoop/share/hadoop”,向Java工程中添加以下JAR包:
(1)”/usr/local/hadoop/share/hadoop/common”目录下的hadoop-common-2.7.1.jar和haoop-nfs-2.7.1.jar;
(2)“/usr/local/hadoop/share/hadoop/common/lib”目录下的所有JAR包;
(3)“/usr/local/hadoop/share/hadoop/hdfs”目录下的haoop-hdfs-2.7.1.jar和haoop-hdfs-nfs-2.7.1.jar;
(4)“/usr/local/hadoop/share/hadoop/hdfs/lib”目录下的所有JAR包。
(5)编写程序:
检测HDFS中是否存在一个文件:
、“HDFSExample”右击,“New->Class”
在“Name”后面输入新建的Java类文件的名称,如“HDFSFileIfExist”;另外特别注意将package的值清空;其他都可以采用默认设置。然后,点击界面右下角“Finish”
测试文件是否存在:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
publicclassHDFSFileIfExist{
publicstaticvoid main(String[] args){
try{
String fileName ="test.txt";
Configuration conf =newConfiguration();
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(newPath(fileName))){
System.out.println("文件存在");
}else{
System.out.println("文件不存在");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行程序时 “Console”面板中还会显示一些类似“log4j:WARN…”的警告信息,不用理会。
(7)应用程序的部署:把Java应用程序生成JAR包,部署到Hadoop平台上运行。
在Hadoop安装目录下新建一个名称为myapp的目录,用来存放自己编写的Hadoop应用程序:
cd /usr/local/hadoop
mkdir myapp
在Eclipse工作界面中,在工程名称“HDFSExample”上点击鼠标右键,在弹出的菜单中选择“Export”,在弹出界面中选择"java"--"Runnable JAR file",点击“Next>”按钮,弹出如图所示界面。
在该界面中,“Launch configuration”用于设置生成的JAR包被部署启动时运行的主类,需要在下拉列表中选择刚才配置的类“HDFSFileIfExist-HDFSExample”。在“Exportdestination”中需要设置JAR包要输出保存到哪个目录,比如,这里设置为“/usr/local/hadoop/myapp/HDFSExample.jar”。在“Libraryhandling”下面选择“Extract required libraries into generatedJAR”。然后,点击“Finish”按钮,会出现如下图所示界面。
可以忽略该界面的信息,直接点击界面右下角的“OK”按钮,启动打包过程。打包过程结束后,会出现一个警告信息界面,如下图所示。
可以忽略该界面的信息,直接点击界面右下角的“OK”按钮。至此,已经顺利把HDFSExample工程打包生成了HDFSExample.jar。
在Linux系统中查看生成的HDFSExample.jar文件:
cd /usr/local/hadoop/myapp
ls
使用hadoop jar命令运行程序:
cd /usr/local/hadoop
./bin/hadoop jar./myapp/HDFSExample.jar
或者也可以使用如下命令运行程序:
cd /usr/local/hadoop
java -jar ./myapp/HDFSExample.jar
命令执行结束后,会在屏幕上显示执行结果“文件不存在”
至此程序部署完成
(8)向java项目中导入源文件
在Eclipse中的hdfsExamples项目的src文件夹上单击鼠标右键,选择 “import”--“General”--“File System”,点击“Next”按钮。然后点击“Browse”按钮,在左侧列表中选择“File System”,在右侧列表中依次双击“home”--“hadoop”文件夹,然后点击“OK”按钮。然后在接下来的窗口中上方的右侧列表中,找到刚才新建的test.java文件,选中其复选框,点击“Finish”按钮。这样就把test.java文件导入到Eclipse中的hdfsExamples项目中了。
4.代码
(1)写入文件
1.
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 classWriteFile{
public staticvoid main(String[] args){
try{
Configuration conf =newConfiguration();
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(newPath(filename));
os.write(buff,0,buff.length);
System.out.println("Create:"+ filename);
os.close();
fs.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
(2)判断文件是否存在
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public classFileIsExist{
public staticvoid main(String[] args){
try{
String filename ="test";
Configuration conf =newConfiguration();
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(newPath(filename))){
System.out.println("文件存在");
}else{
System.out.println("文件不存在");
}
fs.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
(3)读取文件
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 classReadFile{
public taticvoid main(String[] args){
try{
Configuration conf =newConfiguration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs =FileSystem.get(conf);
Path file =newPath("test");
FSDataInputStream getIt = fs.open(file);
BufferedReader d =newBufferedReader(newInputStreamReader(getIt));
String content = d.readLine();//读取文件一行
System.out.println(content);
d.close();//关闭文件
fs.close();//关闭hdfs
}catch(Exception e){
e.printStackTrace();
}
}
}
用命令行进行实验环境练习
1.上传文件至HDFS
如果指定的文件在HDFS中已经存在,由用户指定是追加到原有文件末尾还是覆盖原有的文件。
(1)配置环境变量
配置一下PATH变量,将Hadoop的安装目录加入到PATH变量中,这样就可以在任意目录下直接使用hadoop fs、hdfs等命令了。
切换成Hadoop用户:
su hadoop #切换到hadoop
执行vim ~/.bashrc
,在JAVA环境变量之后加入下面这行代码:
export PATH=$PATH:/usr/local/hadoop/bin:/usr/local/hadoop/sbin
保存后执行source ~/.bashrc使配置生效。
source ~/.bashrc
启动Hadoop
start-dfs.sh
(2)创建本地测试文件
#text.txt:“hello,this is text.txt”,
#local.txt:“hello,this is local.txt”:
cd /home/hadoop
vim text.txt
vim local.txt
(3)检查文件是否存在
hdfs dfs -test -e text.txt
#检查文件是否存在。返回值为1,表示不存在,返回值为0,表示存在
#执行完这一句不会输出结果,需要继续输入命令"echo $?")查看结果
echo $?
(4)将本地的local.txt文件上传到hdfs,并命名为text.txt
(hdfs中目标文件不存在)
#将本地的local.txt文件上传到hdfs,并命名为text.txt
hdfs dfs -appendToFile local.txt text.txt
#再次检查text.txt文件是否存在,echo返回值为0
hdfs dfs -test -e text.txt
echo $?
查看文件内容
#查看hdfs中text.txt文件的内容,结果显示的是本地文件local.txt的内容“hello,this is local.txt”
hdfs dfs -cat text.txt
(5)追加文件(hdfs中目标文件存在)
hdfs dfs -appendToFile local.txt text.txt
hdfs dfs -cat text.txt
hdfsdfs -appendToFile命令,如果hdfs中目标文件不存在,则相当于将本地文件上传到hdfs中,新建目标文件;如果hdfs中目标文件存在,则将本地文件中的内容追加到hdfs的目标文件中。
(6)覆盖文件
#用本地的text.txt文件覆盖hdfs中的text.txt文件
hdfs dfs -copyFromLocal -f text.txt text.txt
#查看hdfs中text.txt文件的内容,结果显示的是本地文件text.txt的内容“hello,this is text.txt”
hdfs dfs -cat text.txt
“如果text.txt文件存在则将local.txt文件的内容追加至text.txt,如果不存在则将local.txt文件的内容覆盖掉text.txt”(如下代码可视为一行代码,在终端中输入第一行代码后,直到输入 fi 才会真正执行):
if $(hdfs dfs -test -e text.txt);
then $(hdfs dfs -appendToFile local.txt text.txt);
else $(hdfs dfs -copyFromLocal -f local.txt text.txt);
fi
(7)源文件:
1.
import org.apache.hadoop.conf.Configuration;
2. import org.apache.hadoop.fs.*;
3. import java.io.*;
4. publicclassHDFSApi{
5. /**
6. * 判断路径是否存在
7. */
8. publicstaticboolean test(Configuration conf,String path)throwsIOException{
9. FileSystem fs =FileSystem.get(conf);
10. return fs.exists(newPath(path));
11. }
12. /**
13. * 复制文件到指定路径
14. * 若路径已存在,则进行覆盖
15. */
16. publicstaticvoid copyFromLocalFile(Configuration conf,String localFilePath,String remoteFilePath)throwsIOException{
17. FileSystem fs =FileSystem.get(conf);
18. Path localPath =newPath(localFilePath);
19. Path remotePath =newPath(remoteFilePath);
20. /*fs.copyFromLocalFile 第一个参数表示是否删除源文件,第二个参数表示是否覆盖 */
21. fs.copyFromLocalFile(false,true, localPath, remotePath);
22. fs.close();
23. }
24. /**
25. * 追加文件内容
26. */
27. publicstaticvoid appendToFile(Configuration conf,String localFilePath,String remoteFilePath)throwsIOException{
28. FileSystem fs =FileSystem.get(conf);
29. Path remotePath =newPath(remoteFilePath);
30. /*创建一个文件读入流 */
31. FileInputStreamin=newFileInputStream(localFilePath);
32. /*创建一个文件输出流,输出的内容将追加到文件末尾 */
33. FSDataOutputStreamout= fs.append(remotePath);
34. /*读写文件内容 */
35. byte[] data =newbyte[1024];
36. int read =-1;
37. while((read =in.read(data))>0){
38. out.write(data,0, read);
39. }
40. out.close();
41. in.close();
42. fs.close();
43. }
44./**
45. * 主函数
46. */
47.publicstaticvoid main(String[] args){
48.Configuration conf =newConfiguration();
49.conf.set("fs.default.name","hdfs://localhost:9000");
50.conf.set("dfs.support.append","true");
51.conf.set("dfs.client.block.write.replace-datanode-on-failure.enable","true");
52.conf.set("dfs.client.block.write.replace-datanode-on-failure.policy","NEVER");
53.
54.String localFilePath ="/home/hadoop/text.txt"; // 本地路径
55.String remoteFilePath ="/user/hadoop/text.txt"; // HDFS路径
56.String choice ="append"; // 若文件存在则追加到文件末尾
57.// String choice ="overwrite"; // 若文件存在则覆盖
58.try{
59./* 判断文件是否存在 */
60.Boolean fileExists =false;
61.if(HDFSApi.test(conf, remoteFilePath)){
62.fileExists =true;
63.System.out.println(remoteFilePath +"已存在.");
64.}else{
65.System.out.println(remoteFilePath +"不存在.");
66.}
67./* 进行处理 */
68.if(!fileExists){// 文件不存在,则上传
69.HDFSApi.copyFromLocalFile(conf, localFilePath, remoteFilePath);
70.System.out.println(localFilePath +"已上传至 "+remoteFilePath);
71.}elseif( choice.equals("overwrite")){ // 选择覆盖
72.HDFSApi.copyFromLocalFile(conf, localFilePath, remoteFilePath);
73.System.out.println(localFilePath +"已覆盖 "+remoteFilePath);
74.}elseif( choice.equals("append")){ // 选择追加
75.HDFSApi.appendToFile(conf, localFilePath, remoteFilePath);
76.System.out.println(localFilePath +"已追加至 "+remoteFilePath);
77.}
78.}catch(Exception e){
79.e.printStackTrace();
80.}
81.}
82.}
查看控制台的输出结果
以上是关于HDFS操作的主要内容,如果未能解决你的问题,请参考以下文章
大数据学习——java代码实现对HDFS文件的readappendwrite操作
VSCode自定义代码片段15——git命令操作一个完整流程