← 返回首页
Hadoop基础教程(五)
发表时间:2022-05-30 00:31:34
HDFS Shell与API

1.HDFS Shell

#查看安全模式状态
hdfs dfsadmin -safemode get

#手工进入安全模式
#安全模式下会对hdfs的保护,会禁止访问hdfs
hdfs dfsadmin -safemode enter

#手工退出安全模式
hdfs dfsadmin -safemode leave

# 显示根目录 / 下的文件和子目录,绝对路径
hadoop fs -ls /

#hadoop fs命令的官方解释为“This command is documented in the File System Shell Guide. It is a synonym for `hdfs dfs` when HDFS is in use.”。
#即fs是一种通用的文件系统操作命令,当文件系统使用hdfs时,hadoop fs和hdfs dfs命令等效。


# 新建文件夹,绝对路径
hadoop fs -mkdir /hello
# 或者使用-p可以创建多级目录
hdfs dfs -mkdir -p /hello/test/haha/xixi

# 上传文件
hadoop fs -put hello.txt /hello/
# 或者
hdfs dfs -put /usr/local/test.txt  /test/

# 下载文件
hadoop fs -get /hello/hello.txt
# 或者,将hdfs中路径文件下载到本地
hdfs dfs -get /test/test.txt

#删除文件
hdfs dfs -rm -r /tez/apache-tez-0.10.1-bin.tar.gz

#删除目录要求目录必须是空的
hdfs dfs -rm -r -f /myvideo/temp

# 输出文件内容
hadoop fs -cat /hello/hello.txt

#显示文件统计信息
hdfs dfs -stat <路径>

2.HDFS回收站

HDFS默认没有开启回收站功能,我们需要在core-site.xml中配置。

<!--开启回收站-->
<property>
    <name>fs.trash.interval</name>
    <!--回收站默认保存一天-->
    <value>1440</value>
</property>

删除文件测试:

[root@master sbin]# hdfs dfs -rm -r /hello/helloworld.txt
2023-09-01 10:47:17,422 INFO fs.TrashPolicyDefault: Moved: 'hdfs://master:9000/hello/helloworld.txt' to trash at: hdfs://master:9000/user/root/.Trash/Current/hello/helloworld.txt

#强制删除文件不经过回收站。
[root@master tools]# hdfs dfs -rm -r -skipTrash  /tools/hadoop-3.1.3.tar.gz 
Deleted /tools/hadoop-3.1.3.tar.gz

3.安全模式

HDFS集群刚启动后会自动进入到安全模式,此时暂时无法执行写操作。可以通过下面命令查看是否处于安全模式和立刻退出安全模式。

[root@master tools]# hdfs dfsadmin -safemode get
Safe mode is OFF
[root@master tools]# hdfs dfsadmin -safemode leave
Safe mode is OFF

4.定时上传日志至HDFS案例

生成当天日志的shell脚本。

#!/bin/bash

#检查日志目录是否存在
if [ -d "/data/logo/" ]; then
  echo "/data/log/目录已经存在"
else
  echo "/data/log/目录不存在"
  mkdir -p /data/log
fi
# 循环向文件中生成数据
count=0
while [ $count -lt 5 ]
do
    # 获取当前时间戳
    today=`date +%Y_%m_%d`
    # 获取当前主机名
    name=`hostname`
    echo this is ${name}_${today}_loginfo_record${count} >> /data/log/access_${today}.log
    # 暂停1秒
    sleep 1
    count=$((count+1))
done

上传日志文件到HDFS的脚本。

#!/bin/bash

# 获取今天日期字符串
today=`date +%Y_%m_%d`
# 拼接日志文件路径信息
logPath=/data/log/access_${today}.log

# 将日期字符串中的_去掉
hdfsPath=/log/${today//_/}
# 在hdfs上创建目录
hdfs dfs -mkdir -p ${hdfsPath}

# 将数据上传到hdfs的指定目录中
hdfs dfs -put  ${logPath} ${hdfsPath}

5.API操作

以Java API为例。

1).测试读取并下载文件。

输出/hello/helloworld.text 文件内容:

hadoop fs -cat /hello/helloworld.txt
HelloWorld!

1)引入依赖

<dependencies>
    <dependency>
         <groupId>org.apache.hadoop</groupId>
         <artifactId>hadoop-client</artifactId>
         <version>3.3.1</version>
    </dependency>
    <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
    </dependency>
</dependencies>

2)编写测试类

package com.simoniu;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;
import java.io.IOException;


public class HdfsClientTest {

    @Test
    public void testGetResource() throws IOException {

        // 1 获取文件系统,并配置参数
        Configuration configuration = new Configuration();
        configuration.set("fs.defaultFS", "hdfs://192.168.56.101:9000");
        FileSystem fs = FileSystem.get(configuration);
        // 打开文件并读取输出
        Path hello = new Path("/hello/helloworld.txt");
        FSDataInputStream ins = fs.open(hello);
        int ch = ins.read();
        while (ch != -1) {
            System.out.print((char)ch);
            ch = ins.read();
        }
        System.out.println();

        //下载文件
        //获取HDFS文件系统的输入流
        FSDataInputStream fis = fs.open(new Path("/hello/helloworld.txt"));
        //获取本地文件的输出流
        FileOutputStream fos = new FileOutputStream("D:"+ File.separator+"uploadFiles"+File.separator+"helloworld_copy.txt");
        //下载文件
        IOUtils.copyBytes(fis,fos,1024,true);
    }

}

运行结果:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
log4j:WARN No appenders could be found for logger (org.apache.htrace.core.Tracer).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
HelloWorld!

如果出现无法连接hdfs://192.168.3.77:9000的连接异常错误,说明core-site.xml和slaves配置文件没有配置成真实内网IP地址。需要修改配置如下:

core-site.xml

<property>
    <name>fs.defaultFS</name>
    <value>hdfs://192.168.3.77:9000</value>
 </property>

slaves

192.168.3.77

2).测试写入文件

    @Test
    public void testWriteFileToHdfs(){
      try {
          //创建一个配置对象
          Configuration conf = new Configuration();
          //指定HDFS的地址
          conf.set("fs.defaultFS", "hdfs://192.168.56.101:9000");
          //获取操作HDFS的对象
          FileSystem fileSystem = FileSystem.get(conf);
          //获取HDFS文件系统的输出流
          FSDataOutputStream fos = fileSystem.create(new Path("/hello/poems.txt"));
          //获取本地文件的输入流
          FileInputStream fis = new FileInputStream("d:"+File.separator+"uploadFiles"+File.separator+"poems.txt");
          //上传文件:通过工具类把输入流拷贝到输出流里面,实现本地文件上传到HDFS
          IOUtils.copyBytes(fis, fos, 1024, true);
      }catch (Exception ex){
          ex.printStackTrace();
      }
    }

注意:如果上传文件至HDFS时报以下错误:

org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied:

这是因为HDFS默认开启了权限校验机制,在hdfs-site.xml中关闭即可。配置如下:

<!--关闭权限校验机制-->
<property>  
    <name>dfs.permissions.enabled</name>  
    <value>false</value>  
</property>  

3).测试删除文件


   @Test
   public void testDeleteFileFromHdfs() {
        try {
            //创建一个配置对象
            Configuration conf = new Configuration();
            //指定HDFS的地址
            conf.set("fs.defaultFS", "hdfs://192.168.56.101:9000");
            //获取操作HDFS的对象
            FileSystem fileSystem = FileSystem.get(conf);
            //删除文件,目录也可以删除
            //如果要递归删除目录,则第二个参数需要设置为true
            //如果是删除文件或者空目录,第二个参数会被忽略
            boolean flag = fileSystem.delete(new Path("/hello/poems.txt"), true);
            if (flag) {
                System.out.println("删除成功!");
            } else {
                System.out.println("删除失败!");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }