Hadoop-JAVA编写HDFS客户端进行HDFS操作

HDFS客户端操作

环境准备

根据电脑操作系统将对应的编译后的jar包放到非中文路径下,我的是Linux因此将Linux编译后的jar放到指定目录下/home/lxj/workspace/hadoop-2.7.0

配置环境变量,然后使其生效

export HADOOP_HOME=/home/lxj/workspace/hadoop-2.7.2
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin

然后创建一个简单的maven项目,jdk使用1.8,将以下依赖导入:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>RELEASE</version>
    </dependency>
        <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.7.2</version>
    </dependency>
    <dependency>
        <groupId>jdk.tools</groupId>
        <artifactId>jdk.tools</artifactId><version>1.8</version>
        <scope>system</scope>
        <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
    </dependency>
</dependencies>

环境测试

创建一个main方法

public class HDFSClient {

    public static void main (String[] args) throws IOException {

        // 1. 获取hdfs客户端对象
        
        // 方法一:此方法需要用到以下的指定集群用户
        Configuration conf = new Configuration();
        // 设置要访问的集群,值可以从已有集群的core-site.xml文件获取,或者直接指定
        // <property>
        //     <name>fs.defaultFS</name>
        //     <value>hdfs://hadoop113:9000</value>
        // </property>
        // 同时本地要配置对应的域名映射
        conf.set("fs.defaultFS", "hdfs://hadoop113:9000");
        FileSystem fs = FileSystem.get(conf);

        // 方法二,一步到位
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop113:9000"), conf, "bd");
        
        
        // 2.hdfs上创建路径
        fs.mkdirs(new Path("/sanguo/shu"));

        // 3.关闭资源
        fs.close();

        System.out.println("over");
    }
}

指定集群对应的用户bd。

IDEA中指定集群用户如下(-DHADOOP_USER_NAME=bd):

在这里插入图片描述

然后运行程序,从网页上可以看到/sanguo/shu目录已经添加成功了
在这里插入图片描述

HDFS参数优先级

HDFS的参数优先级的话,如下:

代码中的Configuration conf = new Configuration()的set方法优先级最高;

src/main/resources目录下的xml文件优先级第二;

集群上的xml优先级最低。

1、例如默认的dfs.replication是3,即默认副本数是3,如果在resources目录下有hdfs-site.xml如下配置文件,则副本数为1

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
    	<name>dfs.replication</name>
    	<value>1</value>
    </property>
</configuration>

2、默认为3,且resources下的文件配置为1,如果在代码中显示配置了副本数的为2的话,那么最终上传之后的副本数为2

Configuration configuration = new Configuration();
configuration.set("dfs.replication", "2");

HDFS常用API的使用

public class HDFSClient {

    public final static String HDFS_URI = "hdfs://hadoop113:9000";
    public final static String HDFS_USER = "bd";
    public final static String FILE_PRE = "/home/lxj/hadoop-data/";
    public final static String HDFS_FILE_PRE = "/sanguo/shu/";

    public static void main (String[] args) throws Exception {

        // 获取hdfs客户端对象
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

        // mkdirs
        // 创建目录
         fs.mkdirs(new Path("/sanguo/shu"));

        // copyFromLocalFile
        // 上传文件
         fs.copyFromLocalFile(getLocalPathByFile("guanyu"), getHDFSPathByFile("guanyu"));

        // copyToLocalFile
        // 下载文件
        // 1、这样下载的话(非本地模式),会多产生一个crc文件,可以用来校验文件的完整性以及正确性
         fs.copyToLocalFile(getHDFSPathByFile("guanyu"), getLocalPathByFile("guanyu_copy"));
        // 2、这个方法有4个参数
        /**
         * delSrc: 默认为false,如果是true的话,将会删除源文件,移动文件实际调用的方法就是false情况的本方法
         * src: 源文件路径
         * dest: 目标文件路径
         * useRowLocalFileSystem: 是否使用本地模式
         */
         fs.copyToLocalFile(false, getHDFSPathByFile("guanyu"), getLocalPathByFile("guanyu_copy2"), true);

        // delete
        // 删除文件
        // 删除文件时,第二个参数任意
         fs.delete(getHDFSPathByFile("guanyu"), false);
        // 删除文件夹时,第二个参数必须为true,表示递归删除
         fs.mkdirs(new Path("/sanguo/han"));
         fs.delete(new Path("/sanguo/han"), true);

        // rename
        // 文件更名
         fs.copyFromLocalFile(getLocalPathByFile("guanyu"), getHDFSPathByFile("guanyu"));
         fs.rename(getHDFSPathByFile("guanyu"), getHDFSPathByFile("guanyunchang"));
        // 文件夹更名
         fs.mkdirs(new Path("/sanguo/han"));
         fs.rename(new Path("/sanguo/han"), new Path("/sanguo/donghan"));

        // listFiles
        // 文件详情查看
        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

        while (listFiles.hasNext()) {
            LocatedFileStatus fileStatus = listFiles.next();

            // 查看文件的名称、权限、长度、块信息等
            System.out.println(fileStatus.getPath().getName()); // 名称
            System.out.println(fileStatus.getPermission()); // 权限
            System.out.println(fileStatus.getLen()); // 长度

            BlockLocation[] blockLocations = fileStatus.getBlockLocations();
            for (BlockLocation blockLocation : blockLocations) {
                String[] hosts = blockLocation.getHosts();
                for (String host : hosts) {
                    System.out.println(host);
                }
            }

            System.out.println("-----------分割线------------------------------");
        }

        // listStatus
        // 判断是文件还是文件夹
        FileStatus[] listStatus = fs.listStatus(new Path("/"));
        for (FileStatus fileStatus : listStatus) {
            if (fileStatus.isFile()) {
                // 文件
                System.out.println("file: " + fileStatus.getPath().getName());
            } else {
                // 文件夹
                System.out.println("dir: " + fileStatus.getPath().getName());
            }
        }


        // 关闭资源
        fs.close();
    }

    private static Path getLocalPathByFile (String filename) {

        return new Path(FILE_PRE + filename);
    }

    private static Path getHDFSPathByFile (String filename) {

        return new Path(HDFS_FILE_PRE + filename);
    }
}

HDFS的I/O流操作

上传文件

此部分代码HDFSClient下

// fs.create(Path) 获取HDFS的输出流,用于文件上传
@Test
public void putFileToHDFS() throws Exception {

    // 获取hdfs客户端对象
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

    // 获取输入流
    FileInputStream fis = new FileInputStream(new File(FILE_PRE + "guanyu"));

    // 获取输出流
    FSDataOutputStream fos = fs.create(new Path("/ioguanyu"));

    // 流的对拷
    IOUtils.copyBytes(fis, fos, conf);

    // 关闭资源
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    fs.close();
}
下载文件

此部分代码HDFSClient下

// fs.open(Path) 获取HDFS的输入流,用于文件下载
@Test
public void getFileToLocal() throws Exception {

    // 获取hdfs客户端对象
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

    // 获取输入流
    FSDataInputStream fis = fs.open(new Path("/ioguanyu"));

    // 获取输出流
    FileOutputStream fos = new FileOutputStream(new File(FILE_PRE + "guanyuio"));

    // 流的对拷
    IOUtils.copyBytes(fis, fos, conf);

    // 关闭资源
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    fs.close();
}
定位文件读取

作用是分块读取HDFS上的大文件,比如一个文件是200MB,而默认的块大小是128MB,那么该文件会被分为两块,一块128MB,另一块是72MB。可以只下载我们需要的块,比如日志文件很大,但是只需要下载最近的一些数据,那么就可以用到定位文件读取了。

// 读取第一块
@Test
public void readFileSeek1() throws Exception {

    // 获取hdfs客户端对象
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

    // 获取输入流
    FSDataInputStream fis = fs.open(new Path("/hadoop-2.7.2.tar.gz"));

    // 获取输出流
    FileOutputStream fos = new FileOutputStream(new File(FILE_PRE + "hadoop-2.7.2.tar.gz.part1"));

    // 流的对拷(只拷贝128M)
    byte[] buf = new byte[1024];
    for (int i = 0; i < 1024 * 128; i++) {
        fis.read(buf);
        fos.write(buf);
    }

    // 关闭资源
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    fs.close();
}

// 读取第二块
// 使用fis.seek(start)来设置读取的起点
@Test
public void readFileSeek2() throws Exception {

    // 获取hdfs客户端对象
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

    // 获取输入流
    FSDataInputStream fis = fs.open(new Path("/hadoop-2.7.2.tar.gz"));

    // 获取输出流
    FileOutputStream fos = new FileOutputStream(new File(FILE_PRE + "hadoop-2.7.2.tar.gz.part2"));

    // 指定读取的起点,读取128M之后的文件
    fis.seek(1024 * 1024 * 128);

    // 流的对拷
    IOUtils.copyBytes(fis, fos, conf);

    // 关闭资源
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    fs.close();
}

两个文件下载成功之后,验证是否下载成功,那么使用cat命令将其拼接来验证。

cat hadoop-2.7.2.tar.gz.part1 hadoop-2.7.2.tar.gz.part2 > hadoop-2.7.2.tar.gz

## 拼接之后的文件能够正常使用,说明下载成功
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值