TOP

springboot上传下载文件(3)--java api 操作HDFS集群+集群配置
2019-01-03 12:12:55 】 浏览:530
Tags:springboot 上传下载 文件 --java api 操作 HDFS 集群 配置

只有光头才能变强!


前一篇文章讲了nginx+ftp搭建独立的文件服务器

但这个服务器宕机了怎么办?

我们用hdfs分布式文件系统来解决这个问题(同时也为hadoop系列开个头)

目录

1、Ubuntu14.04下配置Hadoop(2.8.5)集群环境详解(完全分布式)

1.1、前期准备

1.2、创建用户组

1.3、安装ssh

1.3.1、实现ssh免密操作

1.4、安装jdk

1.5、安装hadoop

1.6、单机测试

2.1、克隆此时的虚拟机

2.2、ssh免密登陆

1、3个虚拟机A,B,C 都进行下面的命令

2.3、修改hosts和hostname文件

1、修改hostname文件

2、修改hosts文件

2.4、在主机上的hadoop中创建文件夹

2.5、在主机上修改hadoop的配置文件

2.6、把修改好的hadoop复杂到从机中

2.7、主机中格式化namenode

2.8、启动hdfs

2.9、查看hdfs进程(命令行+浏览器)

2.10、终止hdfs

2、HDFS常用操作命令

2.1、添加结点

2.2、负载均衡

3、java 操作hdfs集群

3.1、配置application.properties:

3.2、HdfsUtils

3.3、controller层

3.4、报错解决

1)遇见的bug:

java.io.FileNotFoundException: HADOOP_HOME and hadoop.home.dir are unset.

2)上面一个bug解决,但又出了一个新的问题

java.io.IOException: Could not locate executable C:\hadoop-2.8.5\hadoop-2.8.5\bin\winutils.exe in the Hadoop binaries.

3) 关于CDH页面下载HDFS文件地址解析出错

3.5、验证是不是集群


1、Ubuntu14.04下配置Hadoop(2.8.5)集群环境详解(完全分布式)

1.1、前期准备

一台装有虚拟机VMware的win10电脑= =

Ubuntu14.04镜像

先用上面的条件,装出一个Ubuntu14.04的系统虚拟机出来,很简单,过程就省略啦。

一个即可,简单配置之后再克隆2个(现在不用克隆)

1.2、创建用户组

为hadoop集群专门设置一个用户组及用户

$ sudo su root //切换到root权限下

$ adduser hadoop

三台机都需要有相同名字的用户,此处命名为hadoop。 这里先弄一个虚拟机,之后再克隆

ubuntu下可以用adduser或者useradd来添加新用户,后者不会为新用户创建文件夹。

结果截图:

然后

创建用户后需要授权,否则在新用户下用sudo会报错

root用户下:

vim /etc/sudoers

修改文件如下:

代码如下复制代码

# User privilege specification

root ALL=(ALL:ALL) ALL

hadoop ALL=(ALL:ALL) ALL //添加这句话是为了让hadoop用户也能使用sudo。

保存,授权完成

su hadoop (切换的自己的账号)

1.3、安装ssh

根据官方文档的要求要配置ssh

查看是否安装(ssh)openssh-server,否则无法远程连接。

推荐这样,将ssh相关组件一起安装

$sudo apt-get install ssh

其中常用的命令:

#查看ssh安装包情况

dpkg -l | grep ssh

#查看是否启动ssh服务

ps -e | grep ssh

#开启服务

sudo /etc/init.d/ssh start

1.3.1、实现ssh免密操作

因为hadoop运行过程中需要主从机很频繁地用ssh登陆,如果没有无密码登陆会需要一直输入密码

这边先放着,等会我们再来做!!!

1.4、安装jdk

在安装java之前我们需要检查系统中有没有安装java,使用java -version命令来查看是否安装了java,如果安装了其他版本的java请在卸载之后安装java1.8.0。

下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

下载 jdk-8u191-linux-x64.tar.gz

这时我们将这个文件解压缩到/usr/java/目录下(请在解压缩之前新建这个目录)

tar -zxvf jdk-8u191-linux-x64.tar.gz -C /usr/java/

在解压缩之后,配置环境变量 $vim ~/.bashrc

export JAVA_HOME=/usr/java/jdk1.8.0_191

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export PATH=$JAVA_HOME/bin:$PATH

写完环境变量之后使用

$source ~/.bashrc

使环境变量已经生效。

检查$java –version 检查java版本

安装成功

1.5、安装hadoop

下载Hadoop

https://hadoop.apache.org/releases.html

所有版本都有source(源码)和binary(已编译)版本,我选了后者

hadoop-2.8.5.tar.gz

将压缩包解压到/usr/hadoop:

$sudo mkdir /usr/hadoop

$sudo tar zxvf hadop-2.8.5.tar.gz -C /usr/hadoop

#修改bashrc文件

$sudo vim ~/.bashrc

----------------------

#set hadoop environment

export HADOOP_INSTALL=/usr/hadoop/hadoop-2.8.5

export PATH=$PATH:$HADOOP_INSTALL/bin

export PATH=$PATH:$HADOOP_INSTALL/sbin

export HADOOP_MAPRED_HOME=$HADOOP_INSTALL

export HADOOP_COMMON_HOME=$HADOOP_INSTALL

export HADOOP_HDFS_HOME=$HADOOP_INSTALL

---------------------

再执行命令:

$source ~/.bashrc

检查是否安装成功,执行命令,如果出现命令帮助表示成功:hdfs

1.6、单机测试

以上如果配置无误的话,hadoop已经可以单机运行了。可以用自带的例子检验。

hadoop的例子在hadoop/share/hadoop/mapreduce/下,名为hadoop-mapreduce-examples-版本号.jar

$cd /usr/hadoop/hadoop-2.8.5

#创建input目录,复制运行/usr/hadoop/hadoop-2.8.5/etc下所有xml文件到该目录下

$ sudo mkdir input

$ sudo cp etc/hadoop/*.xml input

#运行示例,检测input中符合' '中正则匹配规则的单词出现的次数(这里为dfs开头的单词)

$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.5.jar grep input output 'dfs[a-z.]+'

#查看结果

$ cat output/*

如果正常运行,看到success即成功。hadoop下会自动生成一个output文件夹来存放结果,但是下次运行时不会自动覆盖,再次运行示例时会报错。要先把上次的结果删掉。

报错:Error:JAVA_HOME is not set and could not be found

首先检查~/.bashrc中的JAVA_HOME

https://stackoverflow.com/questions/8827102/hadoop-error-java-home-is-not-set

$sudo vim /usr/local/hadoop/hadoop-2.8.5/etc/hadoop/hadoop-env.sh
export JAVA_HOME=/usr/java/jdk1.8.0_191

再试一次

成功

2.1、克隆此时的虚拟机

简单,省略

2.2、ssh免密登陆

接着上面1.3.1做

https://www.linuxidc.com/Linux/2016-04/130722.htm

SSH主要通过RSA算法来产生公钥与私钥,在数据传输过程中对数据进行加密来保障数

据的安全性和可靠性,公钥部分是公共部分,网络上任一结点均可以访问,私钥主要用于对数据进行加密,以防他人盗取数据。总而言之,这是一种非对称算法,想要破解还是非常有难度的。Hadoop集群的各个结点之间需要进行数据的访问,被访问的结点对于访问用户结点的可靠性必须进行验证,hadoop采用的是ssh的方法通过密钥验证及数据加解密的方式进行远程安全登录操作,当然,如果hadoop对每个结点的访问均需要进行验证,其效率将会大大降低,所以才需要配置SSH免密码的方法直接远程连入被访问结点,这样将大大提高访问效率。

1、3个虚拟机A,B,C 都进行下面的命令

ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

测试:$ssh localhost

exit 退出

2、把A机下的id_rsa.pub复制到B,C机下,在B机的.ssh/authorized_keys文件里,用scp复制。BC机暂时没打算让它们登A机,若要,同理。

$ifconfig

192.168.23.137 A

192.168.23.135 B

192.168.23.136 C

就举一个例子:把A机下的id_rsa.pub复制到B:

hadoop@zj-virtual-machine:~$ scp ~/.ssh/id_dsa.pub hadoop@192.168.23.135:~/.ssh/authorized_keys

结果:

The authenticity of host '192.168.23.135 (192.168.23.135)' can't be established.

ECDSA key fingerprint is 75:7f:24:c6:cf:81:66:da:57:98:21:7b:a8:b3:91:1f.

Are you sure you want to continue connecting (yes/no) yes

Warning: Permanently added '192.168.23.135' (ECDSA) to the list of known hosts.

hadoop@192.168.23.135's password:

id_dsa.pub 100% 615 0.6KB/s 00:00

命令解析:scp 远程复制

-r递归

本机文件地址 app是文件(从根目录开始)

远程主机名@远程主机ip:远程文件地址(从根目录开始)

在A机上测试:

ssh 192.168.23.135

exit

把A机下的id_rsa.pub复制到C:同上

ps:免密码登陆是分用户的(跟.ssh文件夹在用户文件夹下有关),如果机上有多个用户,如abc和hadoop,记得scp和ssh的时候用hadoop用户,另一个用户需要登陆的话需要重新从1开始生成密钥

2.3、修改hosts和hostname文件

先简单说明下配置hosts文件的作用,它主要用于确定每个结点的IP地址,方便后续

master结点能快速查到并访问各个结点。在上述3个虚机结点上均需要配置此文件

1、修改hostname文件

$sudo vim /etc/hostname

这个文件主要是确定这台机的名字,主机改为master,从机改为slave1, slave2,如果之前已经取好名字可以不用改(只要之后对应得上名字就行,并不一定要叫master,slave之类的)

查看当前虚机结点的IP地址是多少

$ifconfig

2、修改hosts文件

$sudo vim /etc/hosts

在文件中添加

127.0.0.1 localhost(一般已有这句,在下面加)

192.168.23.137 master

192.168.23.135 slave1

192.168.23.136 slave2

同时修改三个虚拟机

2.4、在主机上的hadoop中创建文件夹

$cd /usr/hadoop/hadoop-2.8.5
$mkdir tmp

$mkdir tmp/dfs

$mkdir tmp/dfs/data

$mkdir tmp/dfs/name
$sudo chown hadoop:hadoop tmp

2.5、在主机上修改hadoop的配置文件

主要涉及的文件有:

/usr/hadoop/hadoop-2.8.5/etc/hadoop中的:

--------------------------------

hadoop-env.sh
yarn-env.sh
core-site.xml
hdfs-site.xml
yarn-site.xml
mapred-site.xml
slaves

----------------------------------

$cd /usr/hadoop/hadoop-2.8.5/etc/hadoop

#修改其他文件时,把以下hadoop-env.sh替换成其他文件的名字

$cp hadoop-env.sh hadoop-env_old.sh

以下为各文件中的修改内容:

(1)hadoop-env.sh

找到JAVA_HOME的一行

注释掉原来的export, 修改为

export JAVA_HOME=/usr/java/jdk1.8.0_191

(2)yarn-env.sh

找到JAVA_HOME的一行

注释掉原来的export, 修改为

export JAVA_HOME=/usr/java/jdk1.8.0_191

(3core-site.xml

<configuration>

 <!-- 指定hdfs的nameservice为ns1 -->

 <property>

 <name>fs.defaultFS</name>

 <value>hdfs://master:8020</value>

 </property>

 <property>

 <name>io.file.buffer.size</name>

 <value>131072</value>

 </property>

<!-- 指定hadoop临时目录,自行创建 -->

 <property>

 <name>hadoop.tmp.dir</name>

 <value>file:/usr/hadoop/hadoop-2.8.5/tmp</value>

 <description>Abase for other temporary directories.</description>

 </property>

 <property>

 <name>hadoop.proxyuser.hosts</name>

 <value>*</value>

 </property>

 <property>

 <name>hadoop.proxyuser.groups</name>

 <value>*</value>

 </property>



</configuration>

PS:

1、hdfs://master:8020 的master是主机名,和之前的hostname对应,8020是端口号,注意不要占用已用端口就可

2、file: /usr/hadoop/hadoop-2.8.5/tmp 指定到刚刚创建的文件夹

3、所有的配置文件< name >和< value >节点处不要有空格,否则会报错

4、fs.default.name是NameNode的URI。hdfs://主机名:端口/

5、hadoop.tmp.dir :Hadoop的默认临时路径,这个最好配置,如果在新增节点或者其他情况下莫名其妙的DataNode启动不了,就删除此文件中的tmp目录即可。不过如果删除了NameNode机器的此目录,那么就需要重新执行NameNode格式化的命令。

6、以上三点下同

4hdfs-site.xml

---------------------------------

<configuration>



 <property>

 <name>dfs.namenode.secondary.http-address</name>

 <value>master:9001</value>

 </property>

 <property>

 <name>dfs.namenode.name.dir</name>

 <value>file:/usr/hadoop/hadoop-2.8.5/tmp/dfs/name</value>

 </property>

 <property>

 <name>dfs.datanode.data.dir</name>

 <value>file:/usr/hadoop/hadoop-2.8.5/tmp/dfs/data</value>

 </property>

 <property>

 <name>dfs.replication</name>

 <value>3</value>

 </property>

 <property>

 <name>dfs.webhdfs.enabled</name>

 <value>true</value>

 </property>



</configuration>

---------------------------------

dfs.name.dir是NameNode持久存储名字空间及事务日志的本地文件系统路径。 当这个值是一个逗号分割的目录列表时,nametable数据将会被复制到所有目录中做冗余备份。

dfs.data.dir是DataNode存放块数据的本地文件系统路径,逗号分割的列表。 当这个值是逗号分割的目录列表时,数据将被存储在所有目录下,通常分布在不同设备上。

dfs.replication是数据需要备份的数量,默认是3,如果此数大于集群的机器数会出错。

( 5 ) mapred-site.xml.template

------------------

<configuration>



    <property>

 <name>mapreduce.framework.name</name>

 <value>yarn</value>

 </property>

 <property>

 <name>mapreduce.jobhistory.address</name>

 <value>master:10020</value>

 </property>

 <property>

 <name>mapreduce.jobhistory.webapp.address</name>

 <value>master:19888</value>

 </property>



</configuration>

( 6)yarn-site.xml

<configuration>

 <property>

 <name>yarn.nodemanager.aux-services</name>

 <value>mapreduce_shuffle</value>

 </property>

 <property>

<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>

 <value>org.apache.hadoop.mapred.ShuffleHandler</value>

 </property>

 <property>

 <name>yarn.resourcemanager.address</name>

 <value>master:8032</value>

 </property>

 <property>

 <name>yarn.resourcemanager.scheduler.address</name>

 <value>master:8030</value>

 </property>

 <property>

 <name>yarn.resourcemanager.resource-tracker.address</name>

 <value>master:8031</value>

 </property>

 <property>

 <name>yarn.resourcemanager.admin.address</name>

 <value>master:8033</value>

 </property>

 <property>

 <name>yarn.resourcemanager.webapp.address</name>

 <value>master:8088</value>

 </property>

</configuration>

(7) slaves

本文件记录了hadoop中的所有的从机节点

在文件中添加:


slave1

slave2

2.6、把修改好的hadoop复杂到从机中

从机和主机中的hadoop文件夹内容是一样的。如果从机的jdk路径或者hadoop路径不一样,在相应的文件中修改路径(包括之前的bashrc等)即可。为了方便,尽量让所有机上路径相同。所以把主机上的hadoop文件夹放到从机上的同一位置。直接放到usr下可能会没有权限,可以先scp到主文件夹下,再mv过去

$sudo scp -r /usr/hadoop/hadoop-2.8.5 hadoop@192.168.23.135:/home/hadoop

上传完毕后,在从机上会看到主文件夹下多出了hadoop-2.8.5文件夹

打开从机终端:

$cd /usr/hadoop

$mv hadoop-2.8.5 hadoop-2.8.5_old //将之前的改名

$cd ~
$ sudo mv hadoop-2.8.5 /usr/hadoop/

$ sudo chown hadoop:hadoop /usr/hadoop/hadoop-2.8.5

至此检查是否每一台机上都进行过开头所讲的所有步骤中的1-6步骤(复制过去的相当于已进行该步骤,但是若忘记复制前的某步修改或复制后忘记修改内容,如路径、主机名等,都可能导致之后出错)

slave2同上

2.7、主机中格式化namenode

$ cd /usr/hadoop/hadoop-2.8.5

$ bin/hdfs namenode -format

注意只能在初始时格式化namenode,运行中格式化会丢失数据

2.8、启动hdfs

$ start-all.sh

2.9、查看hdfs进程(命令行+浏览器)

在每一台机上运行

$ jps

可以看到,master 上运行着SecondaryNamenode, ResourceManager, NameNode

两个slave上运行着DataNode,NodeManager

浏览器:

默认访问地址:http://namenodeip:50070

参考:https://blog.csdn.net/superzyl/article/details/53741033

2.10、终止hdfs

/usr/local/hadoop$ stop-all.sh

PS:关于防火墙:有些博客提到了关闭防火墙,我配置时并没有遇到问题所以跳过了该步骤

至此配置环境成功

参考:https://blog.csdn.net/ycisacat/article/details/53325520

2、HDFS常用操作命令

hdfs dfs -ls 列出HDFS下的文件

hadoop dfs -ls in 列出HDFS下某个文档中的文件

hadoop dfs -put test1.txt test 上传文件到指定目录并且重新命名,只有所有的DataNode都接收完数据才算成功

hadoop dfs -get in getin 从HDFS获取文件并且重新命名为getin,同put一样可操作文件也可操作目录

hadoop dfs -rmr out 删除指定文件从HDFS上

hadoop dfs -cat in/* 查看HDFS上in目录的内容

hadoop dfsadmin -report 查看HDFS的基本统计信息,结果如下

hadoop dfsadmin -safemode leave 退出安全模式

hadoop dfsadmin -safemode enter 进入安全模式

=====================

命令在与bin目录同级的目录下使用:(我没陪环境变量)

hdfs dfs –ls / :查看根目录文件

hdfs dfs -ls /tmp/data:查看/tmp/data目录

hdfs dfs -cat /tmp/a.txt :查看 a.txt,与 -text 一样

hdfs dfs -mkdir dir:创建目录dir

hdfs dfs -rmdir dir:删除目录dir

2.1、添加结点

可扩展性是HDFS的一个重要特性,首先在新加的节点上安装hadoop,然后修改$HADOOP_HOME/conf/master文件,加入 NameNode主机名,然后在NameNode节点上修改$HADOOP_HOME/conf/slaves文件,加入新加节点主机名,再建立到新加节点无密码的SSH连接

运行启动命令:

start-all.sh

然后可以通过http://(Masternode的主机名):50070查看新添加的DataNode

2.2、负载均衡

start-balancer.sh,可以使DataNode节点上选择策略重新平衡DataNode上的数据块的分布

结束语:遇到问题时,先查看logs,很有帮助。

3、java 操作hdfs集群

参考:https://my.oschina.net/zss1993/blog/1574505

https://gitee.com/MaxBill/hadoop/blob/master/src/main/java/com/maxbill/hadoop/hdfs/HdfsUtils.java

http://blog.51cto.com/jaydenwang/1842908

前提:配置好hadoop集群

3.1、配置application.properties:

#HDFS相关配置
hdfs.defaultfs=fs.defaultFS
hdfs.host=hdfs://192.168.23.137:8020
hdfs.uploadPath=/user/hadoop/

3.2、HdfsUtils

package jit.hf.agriculture.util;



import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.*;

import org.apache.hadoop.io.IOUtils;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;



import java.io.InputStream;

import java.net.URI;



/**

* @Auther: zj

* @Date: 2018/10/30 12:54

* @Description: hdfs工具类

*/

@Component

public class HdfsUtils {



 @Value( "${hdfs.uploadPath}" )

 private String userPath;



 @Value( "${hdfs.host}" )

 private String hdfsPath;



 public void test1(){

 System.out.println( userPath);

 System.out.println( hdfsPath );

 }



 /**

 * @功能 获取HDFS配置信息

 * @return

 */

 private Configuration getHdfsConfig() {

 Configuration config = new Configuration();



 return config;

 }



 /**

 * @功能 获取FS对象

 */

 private FileSystem getFileSystem() throws Exception {

 //客户端去操作hdfs时,是有一个用户身份的,默认情况下,hdfs客户端api会从jvm中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=hadoop

 //FileSystem hdfs = FileSystem.get(getHdfsConfig());

 //也可以在构造客户端fs对象时,通过参数传递进去

 FileSystem hdfs = FileSystem.get(new URI(hdfsPath), getHdfsConfig(), "hadoop");

 return hdfs;

 }



 /**

 * 递归创建目录

 *

 */

 public void mkdir(String path) throws Exception {

 FileSystem fs = getFileSystem();

 Path srcPath = new Path(path);

 boolean isOk = fs.mkdirs(srcPath);

 if (isOk) {

 System.out.println("create dir success...");

 } else {

 System.out.println("create dir failure...");

 }

 fs.close();

 }



 /**

 * 在HDFS创建文件,并向文件填充内容

 */

 public void createFile(String filePath, byte[] files){

 try {

 FileSystem fs = getFileSystem();

 //目标路径

 Path path = new Path( filePath );

 //打开一个输出流

 FSDataOutputStream outputStream = fs.create( path );

 outputStream.write( files );

 outputStream.close();

 fs.close();

 System.out.println( "创建文件成功!" );

 } catch (Exception e) {

 System.out.println( "创建文件失败!" );

 }

 }



 /**

 * 读取HDFS文件内容

 */

 public void readFile(String filePath) throws Exception {

 FileSystem fs = getFileSystem();

 Path path = new Path(filePath);

 InputStream in = null;

 try {

 in = fs.open(path);

 //复制到标准输出流

 IOUtils.copyBytes(in, System.out, 4096, false);

 System.out.println( "\n读取文件成功!" );

 } catch (Exception e) {

 System.out.println( "\n读取文件失败!" );

 }

 finally

 {

 IOUtils.closeStream(in);

 }

 }



 /**

 * 读取HDFS目录详细信息

 */

 public void pathInfo(String filePath) throws Exception {

 FileSystem fs = getFileSystem();

 FileStatus[] listStatus = fs.listStatus(new Path(filePath));

 for (FileStatus fileStatus : listStatus) {

 System.out.println(fileStatus.getPath() + ">>>>>" + fileStatus.toString());

 }

 }



 /**

 * 读取HDFS文件列表

 */

 public void listFile(String filePath) throws Exception {

 FileSystem fs = getFileSystem();

 //递归找到所有的文件

 RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path(filePath), true);

 while (listFiles.hasNext()) {

 LocatedFileStatus next = listFiles.next();

 String name = next.getPath().getName();

 Path path = next.getPath();

 System.out.println(name + "---" + path.toString());

 }

 }



 /**

 * 文件重命名

 */

 public void renameFile(String oldName, String newName) throws Exception {

 FileSystem fs = getFileSystem();

 Path oldPath = new Path(oldName);

 Path newPath = new Path(newName);

 boolean isOk = fs.rename(oldPath, newPath);

 if (isOk) {

 System.out.println("rename success...");

 } else {

 System.out.println("rename failure...");

 }

 fs.close();

 }



 /**

 * 删除指定文件

 */

 public void deleteFile(String filePath) throws Exception {

 FileSystem fs = getFileSystem();

 Path path = new Path(filePath);

 boolean isOk = fs.deleteOnExit(path);

 if (isOk) {

 System.out.println("delete success...");

 } else {

 System.out.println("delete failure...");

 }

 fs.close();

 }



 /**

 * 上传文件

 */

 public void uploadFile(String fileName, String uploadPath) throws Exception {

 FileSystem fs = getFileSystem();

 //上传路径

 Path clientPath = new Path(fileName);

 //目标路径

 Path serverPath = new Path(uploadPath);

 //调用文件系统的文件复制方法,前面参数是指是否删除原文件,true为删除,默认为false

 fs.copyFromLocalFile(false, clientPath, serverPath);

 fs.close();

 System.out.println( "上传文件成功!" );

 }



 /**

 * 下载文件

 */

 public void downloadFile(String fileName, String downPath) throws Exception {

 FileSystem fs = getFileSystem();

 fs.copyToLocalFile(new Path(fileName), new Path(downPath));

 fs.close();

 System.out.println( "下载文件成功!" );

 }



 /**

 * 判断文件是否存在

 */

 public boolean existFile(String FileName) throws Exception {

 FileSystem hdfs = getFileSystem();

 Path path = new Path(FileName);

 boolean isExists = hdfs.exists(path);

 return isExists;

 }

}

3.3、controller层

package jit.hf.agriculture.controller;


import jit.hf.agriculture.util.HdfsUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;





/**

* @Auther: zj

* @Date: 2018/10/30 12:52

* @Description:

*/

@RestController

public class HdfsController {



 @Autowired

 private HdfsUtils hdfsUtils;



 //测试配置文件注入是否有效

 @GetMapping("/hdfs/test1")

 public void HdfsTest1(){

 hdfsUtils.test1();

 }



 /**

 * hdfs 创建目录

 *

 * 测试用例- - -

 * dir: aaa

 */

 @PostMapping("/hdfs/mkdir")

 public void HdfsMkdir(@RequestParam("dir") String path) throws Exception {

 hdfsUtils.mkdir( path );

 }



 /**

 * 在HDFS创建文件,并向文件填充内容

 *

 * 测试用例- - -

 * filepath: aaa/a.text

 * content: hello world

 */

 @PostMapping("/hdfs/vim")

 public void HdfsVim(@RequestParam("filepath") String filepath,

 @RequestParam(value = "content",required=false,defaultValue = "") String content

 ) throws Exception {

 hdfsUtils.createFile( filepath,content.getBytes() );

 }



 /**

 * 读取HDFS文件内容,cat

 * @param filepath

 * @throws Exception

 *

 * 测试用例- - -

 *filepath: aaa/a.text

 */

 @GetMapping("hdfs/cat")

 public void HdfsCat(@RequestParam("filepath") String filepath) throws Exception {

 hdfsUtils.readFile( filepath );

 }



 /**

 * 显示HDFS目录详细信息(包括目录下的文件和子目录)

 * @param filepath

 * @throws Exception

 *

 * 测试用例- - -

 * filepath:aaa

 */

 @GetMapping("hdfs/catdir")

 public void HdfsAndCatDir(@RequestParam("filepath") String filepath) throws Exception {

 hdfsUtils.pathInfo( filepath );

 }



 /**

 * 读取hdfs 指定目录下的文件列表

 * @param filepath

 * @throws Exception

 *

 * 测试用例- - -

 * filepath:aaa

 */

 @GetMapping("hdfs/ls")

 public void HdfsLs(@RequestParam("filepath") String filepath) throws Exception {

 hdfsUtils.listFile( filepath );

 }



 /**

 * 文件重命名

 *

 * 测试用例- - -

 * oldName:aaa/b.text

 * newName:aaa/c.text

 */

 @PostMapping("hdfs/renameFile")

 public void HdfsRenameFile(@RequestParam("oldName") String oldName,

 @RequestParam("newName") String newName) throws Exception {

 hdfsUtils.renameFile( oldName,newName );

 }



 /**

 * 删除指定文件

 * @param filepath

 * @throws Exception

 *

 * 测试用例

 * filepath:aaa/c.text

 */

 @GetMapping("hdfs/deleteFile")

 public void HdfsDeleteFile(@RequestParam("filepath") String filepath) throws Exception {

 hdfsUtils.deleteFile( filepath );

 }



 /**

 * 上传文件

 * @param fileName

 * @param uploadFile

 * @throws Exception

 *

 * 测试用例

 *

 * fileName: C:\\Users\\zj\\Desktop\\hello.txt

 * uploadName:aaa

 */

 @PostMapping("hdfs/uploadFile")

 public void UploadFile(@RequestParam("fileName") String fileName,

 @RequestParam("uploadFile") String uploadFile) throws Exception {

 hdfsUtils.uploadFile( fileName,uploadFile );

 }



 /**

 * 下载文件

 * @param fileName

 * @param downPath

 * @throws Exception

 *

 * 测试用例

 * fileName:aaa/hello.txt

 * downPath:C:\\

 */

 @PostMapping("hdfs/downloadFile")

 public void DownloadFile(@RequestParam("fileName") String fileName,

 @RequestParam("downPath") String downPath) throws Exception {

 hdfsUtils.downloadFile( fileName, downPath);

 }



 /**

 * 判断文件是否存在

 *

 * 测试用例

 *

 */

 @GetMapping("hdfs/existFile")

 public void ExistFile(@RequestParam("fileName") String filName) throws Exception {

 hdfsUtils.existFile( filName );

 }





}

3.4、报错解决

1)遇见的bug:

java.io.FileNotFoundException: HADOOP_HOME and hadoop.home.dir are unset.

参考解决方案:https://blog.csdn.net/ycf921244819/article/details/81706119

https://www.cnblogs.com/huxinga/p/6875929.html

将虚拟机上的hadoop-2.8.5解压到windows上

放到c:/agriculture目录下

添加

public class AgricultureApplication {



 public static void main(String[] args) {

 System.setProperty("hadoop.home.dir", "C:\\agriculture\\hadoop-2.8.5");

 SpringApplication.run(AgricultureApplication.class, args);

 }

}

2)上面一个bug解决,但又出了一个新的问题

java.io.IOException: Could not locate executable C:\hadoop-2.8.5\hadoop-2.8.5\bin\winutils.exe in the Hadoop binaries.

需要下载winutils.exe hadoop.dll等组件放在hadoop安装目录的bin当中。下载地址:https://github.com/srccodes/hadoop-common-2.2.0-bin

虽然是2.2.0的,但是亲测试可用的。下载完毕解压,将里面的bin里面的全部复制,然后拷贝到hadoop安装目录的bin当中,如果有相同的替换掉就是了。

解决

还有一个警告

Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

解决可参考https://www.cnblogs.com/kevinq/p/5103653.html

这个我没做

3) 关于CDH页面下载HDFS文件地址解析出错

解决方案:

https://blog.csdn.net/looc_246437/article/details/77480312

3.5、验证是不是集群

在hdfsUtils中添加:

/**

* 获取HDFS集群上所有节点名称信息

* @throws Exception

*/

public void getListNode() throws Exception {

 FileSystem fs = getFileSystem();



 DistributedFileSystem hdfs = (DistributedFileSystem)fs;

 DatanodeInfo[] dataNodeStats = hdfs.getDataNodeStats();



 for(int i=0;i<dataNodeStats.length;i++){

 System.out.println("DataNode_"+i+"_Name:"+dataNodeStats[i].getHostName());

 }


在hdfscontroller中添加:

/**

* 获取HDFS集群上所有节点名称信息

* @throws Exception

*/

@GetMapping("hdfs/getListNode")

public void HdfsGetListNode() throws Exception {

 hdfsUtils.getListNode();

}

测试:

表明这是集群


springboot上传下载文件(3)--java api 操作HDFS集群+集群配置 https://www.cppentry.com/bencandy.php?fid=115&id=202233

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇hadoop 2.8 hdfs 命令错误总结 下一篇hdfs,mapreduce相关流程总结