springboot上传下载文件(3)--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 [email protected]:~/.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.

[email protected]'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 [email protected]:/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();

}

测试:

表明这是集群

猜你喜欢

转载自blog.csdn.net/qq_41603102/article/details/83614769
今日推荐