Hadoop笔记:Java API 操作HDFS文件大集合

大数据笔记:Java API 操作HDFS文件大集合

标签: 大数据

  • 大数据笔记:Java API 操作HDFS文件大集合
    • JAVAAPI操作HDFS环境搭建
    • JAVA操作在hdfs上创建一个目录
      • 代码展示
      • 文档分析
      • 结果
    • 创建一个文件并写入内容
      • 创建文件
      • 写入内容
      • 代码
    • 查看HDFS的内容
      • 命令行查看
      • java操作
    • 删除文件
    • 文件重命名
    • 上传本地文件到HDFS
      • 小文件直接上传
      • 大文件进度条
    • 下载HDFS上的文件到本地
    • 查看某个目录下的所有文件


JAVAAPI操作HDFS环境搭建

IDEA + Maven创建java工程

我们使用maven,选择maven的 QuickStart 来创建一个maven。

然后在选择setting.xml时,可以选择默认的,也可以选择自己的,不论如何,切记要将maven下载的镜像换成阿里云等国内的。

然后就生成了maven工程。

在pom.xml中添加依赖关系。

首先在properties标签中新建一个标签,为了方便后面的引用:

<hadoop.version>2.6.0-cdh5.7.0hadoop.version>

然后写一个repository元素,repository就是个仓库。maven里有两种仓库,本地仓库和远程仓库。远程仓库相当于公共的仓库,本地仓库主要起缓存作用。当向仓库请求插件或依赖的时候,会先检查本地仓库里是否有。如果有则直接返回,否则会向远程仓库请求,并做缓存。这里就是在pom.xml文件中指定远程仓库。如果没指定,默认会到http://repo1.maven.org/maven2这个地方去请求插件和依赖包。

这里指定:

  <repositories>
    <repository>
      <id>clouderaid>
      <url>https://repository.cloudera.com/artifactory/cloudera-reposurl>
    repository>
  repositories>

然后就是添加依赖:

    <dependency>
      <groupId>org.apache.hadoopgroupId>
      <artifactId>hadoop-clientartifactId>
      <version>${hadoop.version}version>
    dependency>

让maven自己去下载吧!当然下载的过程会出现一些问题,也都解决了。

JAVA操作在hdfs上创建一个目录

这个时候我们就需要把java程序和hadoop服务器连接起来。

首先我们要启动hdfs。然后在创建一个test文件。先看代码,再分析。

代码展示

package com.japson.hadoop.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.net.URI;

/**
 * Created by japson on 5/26/2018.
 * Hadoop HDFS Java API 操作
 */
public class HDFSApp {

    // HDFS_PATH 很重要!是访问连接HDFS的关键
    public static final String HDFS_PATH = "hdfs://192.168.0.117:8020";

    // 必需的FileSystem类
    FileSystem fileSystem = null;
    // 配置对象
    Configuration configuration = null;

    /**
     * 初始化一些资源
     */
    @Before
    public void setUp() throws Exception{
        configuration = new Configuration();
        // 获取一个fileSystem对象,这就相当于建立连接了
        fileSystem = FileSystem.get(new URI(HDFS_PATH),configuration,"japson");
        System.out.println("HDFSApp.setUp");
    }

    /**
     * 创建HDFS目录
     * @throws Exception
     */
    @Test
    public void mkdir() throws Exception {
        // 创建一个新的目录,参数为路径
        fileSystem.mkdirs(new Path("/hdfsapi/test3"));
        System.out.println("mkdir已执行");
    }


    /**
     * 释放资源
     */
    @After
    public void tearDown() throws Exception {
        configuration = null;
        fileSystem = null;
        System.out.println("HDFSApp.tearDown");
    }

}

文档分析

首先我们要引入两个关键的类:org.apache.hadoop.fs.FileSystemorg.apache.hadoop.conf.Configuration

One by one:

org.apache.hadoop.fs.FileSystem:

An abstract base class for a fairly generic filesystem. It may be implemented as a distributed filesystem, or as a “local” one that reflects the locally-connected disk. The local version exists for small Hadoop instances and for testing.
All user code that may potentially use the Hadoop Distributed File System should be written to use a FileSystem object or its successor, FileContext.

The local implementation is LocalFileSystem and distributed implementation is DistributedFileSystem. There are other implementations for object stores and (outside the Apache Hadoop codebase), third party filesystems.

大体意思就是说:

  • 这是一个比较通用的文件系统的抽象基类,可以实现分布式系统或者本地连接磁盘,本地版本可以做hadoop的小测试。

  • 要想使用HDFS,那么就得使用这个FileSystem的对象或者子类对象。

  • 本地实现是LocalFileSystem,分布式实现是DistributedFileSystem。剩下的还有其他第三方实现。

那么现在我就要使用这个方法:

static FileSystem get(URI uri, Configuration conf, String user)

该方法通过文件系统的URI、要使用的Configuration对象和用户名(Linux的,需要权限)来获取一个FileSystem对象。

org.apache.hadoop.conf.Configuration

在API中对于这个类的介绍:

Provides access to configuration parameters.

对配置参数提供访问。

Configuration做为Hadoop的一个基础功能承担着重要的责任,为Yarn、HSFS、MapReduce、NFS、调度器等提供参数的配置、配置文件的分布式传输(实现了Writable接口)等重要功能。

Hadoop实现了一个自己的加载配置文件的功能的Configuration类:org.apache.hadoop.conf.Configuration。其实也就是我们之前的core-site.xml等配置文件。

结果

我们在HDFS中查看:

[japson@localhost hadoop-2.6.0-cdh5.7.0]$ hdfs dfs -ls -R /
18/05/26 00:30:27 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
drwxr-xr-x   - japson supergroup          0 2018-05-25 20:46 /hdfsapi
drwxr-xr-x   - japson supergroup          0 2018-05-25 20:46 /hdfsapi/test3
-rw-r--r--   1 japson supergroup         48 2018-05-25 20:44 /hello.txt

创建一个文件并写入内容

创建文件

我们所有的操作都是在fileSystem的基础上的,我们使用下面的方法来创建文件:

public FSDataOutputStream create(Path f) throws IOException {
        return this.create(f, true);
    }

需要我们传入要创建的文件的路径。

写入内容

创建文件的方法有一个 FSDataOutputStream 类型的返回值。

因此我们创建一个对象将其接住,其实这就是一个输出流,我们就当做输出流来写文件就好了。

FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test3/a.txt"));
outputStream.write("hello hadoop".getBytes());
outputStream.flush();
outputStream.close();

要注意,没有String的参数类型,需要转为字节数组,记得flush和close。

代码

    /**
     * 创建一个文件并写入内容
     * @throws Exception
     */
    @Test
    public void create() throws Exception {
        FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test3/a.txt"));
        outputStream.write("hello hadoop".getBytes());
        outputStream.flush();
        outputStream.close();
    }

查看HDFS的内容

命令行查看

对于之前我们创建的文件,我们可以通过命令行查看其内容

[japson@localhost hadoop-2.6.0-cdh5.7.0]$ hdfs dfs -text /hdfsapi/test3/a.txt
18/05/26 00:39:34 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
hello hadoop

java操作

fileSytem中右一个open方法,是可以将指定路径的内容返回为一个输入流的。

对于一个输入流,我们借助Hadoop的IOUtils来把输入流读到的内容拷贝到控制台

    /**
     * 查看HDFS文件的内容
     * @throws Exception
     */
    @Test
    public void cat() throws Exception {
        FSDataInputStream inputStream = fileSystem.open(new Path("/hdfsapi/test3/a.txt"));
        IOUtils.copyBytes(inputStream,System.out,1024);
        inputStream.close();

    }

删除文件

第二个参数为递归地删除文件。

    /**
     * 删除文件
     * @throws Exception
     */
    @Test
    public void delete() throws Exception {

        fileSystem.delete(new Path("/hdfsapi/test/a.txt"),true);

    }

文件重命名

fileSystem.rename(oldPath,newPath);,需要注意的是:每次只能修改一个目录名或文件名,不能同时修改两个及以上。

    /**
     * 文件重命名
     * @throws Exception
     */
    @Test
    public void rename() throws Exception {
        Path oldPath = new Path("/hdfsapi/test3/a.txt");
        Path newPath = new Path("/hdfsapi/test3/b.txt");
        fileSystem.rename(oldPath,newPath);
    }

上传本地文件到HDFS

小文件直接上传

注意,这里的本地文件,指的就是java的本地环境,而不是服务器的。

使用fileSystem.copyFromLocalFile(localPath,hdfsPath);方法。

    /**
     * 上传本地文件到HDFS
     * @throws Exception
     */
    @Test
    public void copyFromLocalFile() throws Exception {
        Path localPath = new Path("E:\\IntelliJ IDEA\\hadoopTest1\\localText.txt");
        Path hdfsPath = new Path("/hdfsapi/test");

        fileSystem.copyFromLocalFile(localPath,hdfsPath);
    }

大文件进度条

我们就不使用fileSystem.copyFromLocalFile(localPath,hdfsPath);了。

我们先将要上传的文件放入输入流,然后用输出流写,并在参数中选择输出进度条。

然后使用IOUtils,将输入流的内容拷贝到输出流:

    /**
     * 上传本地大文件且需要进度条
     * @throws Exception
     */
    @Test
    public void copyFromLocalFileWithProgress() throws Exception {
        InputStream in = new BufferedInputStream(new FileInputStream(new File("D:\\迅雷下载\\逃避可耻却有用1.mp4")));
        FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test/gakki.mp4"),
                new Progressable() {
                    @Override
                    public void progress() {
                        System.out.print(".");   // 带进度提醒
                    }
                });
        IOUtils.copyBytes(in,outputStream,4096);
    }

下载HDFS上的文件到本地

    /**
     * 下载HDFS文件到本地
     * @throws Exception
     */
    @Test
    public void copyToLocalFile() throws Exception {
        Path localPath = new Path("E:\\IntelliJ IDEA\\hadoopTest1\\download.txt");
        Path hdfsPath = new Path("/hdfsapi/test/b.txt");
        fileSystem.copyToLocalFile(hdfsPath,localPath);
    }

查看某个目录下的所有文件

    /**
     * 查看某个目录下的所有文件
     * @throws Exception
     */
    @Test
    public void listFiles() throws Exception {
        FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/hdfsapi/test"));
        for (FileStatus fileStatus : fileStatuses) {
            String isDir = fileStatus.isDirectory() ? "文件夹" : "文件";
            short replication = fileStatus.getReplication();
            long len = fileStatus.getLen();
            String path = fileStatus.getPath().toString();

            System.out.println(isDir + "\t" + replication + "\t" + len + "\t" + path);
        }
    }

输出:

文件  3   12  hdfs://192.168.0.103:8020/hdfsapi/test/a.txt

你可能感兴趣的:(Hadoop学习以及踩坑记录)