hadoop离线阶段(第八节—1)通过JavaAPI操作hdfs

1300-黄同学

发表文章数:85

热门标签

首页 » 大数据 » 正文

JavaAPI操作hdfs的maven项目创建

对于hadoop的maven依赖坐标,最好到CDH5.14.X maven坐标库找,这是cloudera整理出来的坐标库,是针对CDH版本的hadoop的,而https://mvnrepository.com/的上的Hadoop的maven坐标是针对apache版本。
以下是本实验创建maven的pom.xml:

<!-- 指定远程仓库,保证依赖都来自cloudera -->
<repositories>
    <repository>
        <id>cloudera</id>
        <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
</repositories>

<!-- 添加依赖 -->
<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.6.0-mr1-cdh5.14.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.6.0-cdh5.14.0</version>
    </dependency>
   
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.6.0-cdh5.14.0</version>
    </dependency>


    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-mapreduce-client-core</artifactId>
        <version>2.6.0-cdh5.14.0</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>6.14.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<!-- 添加插件 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
                <!--    <verbal>true</verbal>-->
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

编辑好maven,等待依赖加入完毕后,直接创建测试类,开始测试javaAPI的功能。

测试从hdfs下载文件的API

@Test
public void downHdfsFile() throws IOException //从hdfs系统下载文件的方法
{
    /*
    这个方法会抛出winutils异常,
    因为代码在windows机器上执行,
    但是windows机器并没有hadoop环境,
    需要在windows机器上装hadoop环境
     */

    //注册hdfs驱动文件
    URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    //对指定hdfs路径的文件创建一个输入流
    InputStream input=new URL("hdfs://node01:8020/test/input/install.log").openStream();
    //创建一个输出流来接受从hdfs下载的文件
    OutputStream output=new FileOutputStream("E://hdfsdown.txt");
    //使用org.apache.common.io包下工具类IOUtils,将输入流的文件写入到输出流
    IOUtils.copy(input,output);
    //使用org.apache.common.io包下工具类IOUtils关闭两个文件流
    IOUtils.closeQuietly(input);
    IOUtils.closeQuietly(output);

}

以上方法会抛出winutils异常,如下图
hadoop离线阶段(第八节—1)通过JavaAPI操作hdfs
解决这个问题的方法详见转载自zxzLife

测试通过FileSystem抽象类获取hdfs文件系统

@Test
public void getFileSystem1() throws IOException //使用FileSystem获取hdfs文件系统的方法1
{
    Configuration configuration=new Configuration();
    configuration.set("fs.defaultFS","hdfs://node01:8020");
    //单参数get方法获取hdfs文件系统
    FileSystem fs=FileSystem.get(configuration);
    System.out.println(fs.toString());
    fs.close();
}

@Test
public void getFileSystem2() throws IOException //使用FileSystem获取hdfs文件系统的方法2
{
    Configuration configuration;
    configuration = new Configuration();
    //两个参数get方法获取hdfs文件系统
    FileSystem fs=FileSystem.get(URI.create("hdfs://node01:8020"),configuration);
    System.out.println(fs.toString());
    fs.close();
}

@Test
public void getFileSystem3() throws IOException //使用FileSystem获取hdfs文件系统的方法3
{
    Configuration configuration=new Configuration();
    configuration.set("fs.defaultFS","hdfs://node01:8020");
    //单参数newInstance方法获取hdfs文件系统
    FileSystem fs=FileSystem.newInstance(configuration);
    System.out.println(fs.toString());
    fs.close();
}

@Test
public void getFileSystem4() throws IOException //使用FileSystem获取hdfs文件系统的方法4
{
    Configuration configuration=new Configuration();
    //双参数newInstance方法获取hdfs文件系统
    FileSystem fs=FileSystem.newInstance(URI.create("hdfs://node01:8020"),configuration);
    System.out.println(fs.toString());
    fs.close();
}

效果相同,但推荐使用newInstance的两个参数的方法,因为简便好记。

遍历hdfs指定目录下的所有文件(包括子文件夹的文件)

方法1,递归

@Test
public void listAllFiles1() throws IOException  //递归输出所有hdfs根目录下所有文件的路径
{
    FileSystem fs=FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    FileStatus[] fileStatuses=fs.listStatus(new Path("hdfs://node01:8020/"));
    for (FileStatus status:fileStatuses)
    {
        if (status.isDirectory())
            getDirs(status.getPath(),fs);
        else
            System.out.println(status.getPath());
    }
    fs.close();
}

private void getDirs(Path path,FileSystem fs) throws IOException
{
    FileStatus[] fileStatuses=fs.listStatus(path);
    for(FileStatus s:fileStatuses)
    {
        if(s.isDirectory())
            getDirs(s.getPath(),fs);
        else
            System.out.println(s.getPath());
    }
}

方法2,FileSystem自带的listFiles方法

@Test
public void listAllFiles2() throws IOException //使用FileSystem自带的listFiles方法获取所有hdfs根目录下所有文件的路径
{
    FileSystem fs=FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    RemoteIterator<LocatedFileStatus> remoteIterator =
            fs.listFiles(new Path("hdfs://node01:8020/"),true); //true表示递归子文件夹
    while(remoteIterator.hasNext())
    {
        System.out.println(remoteIterator.next().getPath());
    }
    fs.close();
}

从hdfs下载文件到本地

前面测试过使用文件流的方式下载hdfs的文件,这里是使用FileSystem自带的copyToLocalFile方法

@Test
public void downHdfsFile2() throws IOException //从hdfs系统下载文件,使用FileSystem自带的copyToLocalFile方法
{
    FileSystem fs=
            FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    fs.copyToLocalFile(new Path("hdfs://node01:8020/test/input/install.log"),
            new Path("E://hdfsdown2.txt"));
    fs.close();
}

通过javaAPI创建hdfs系统的目录

@Test
public void createHdfsDir() throws IOException  //在hdfs系统创建目录
{
    FileSystem fs=
            FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    fs.mkdirs(new Path("hdfs://node01:8020/javatest/mytest"));
    fs.close();
} //这个方法叫mkdirs,可见不管是多层目录还是单层目录都适用

从本地向hdfs上传文件

方法1,使用FileSystem自带的copyFromLocalFile方法

@Test
public void uploadHdfsFile1() throws IOException //向hdfs上传文件,使用FileSystem自带的copyFromLocalFile方法
{
    FileSystem fs=
            FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    fs.copyFromLocalFile(new Path("E://hdfsdown.txt"),
            new Path("hdfs://node01:8020/javatest/mytest"));
    fs.close();
}

方法2,使用文件流

@Test
public void uploadHdfsFile2() throws IOException //向hdfs上传文件,文件流的形式
{
    FileSystem fs=
            FileSystem.newInstance(URI.create("hdfs://node01:8020"),new Configuration());
    //用本地文件创建输入流
    InputStream input=new FileInputStream("E://hdfsdown2.txt");
    //通过给FileSystem的create方法创建一个输出流,路径位于hdfs系统上
    FSDataOutputStream fsDataOutputStream=
            fs.create(new Path("hdfs://node01:8020/javatest/mytest/upload.txt"));
    //使用org.apache.common.io包下工具类IOUtils,将输入流的文件写入到输出流
    IOUtils.copy(input,fsDataOutputStream);
    //使用org.apache.common.io包下工具类IOUtils关闭两个文件流
    IOUtils.closeQuietly(input);
    IOUtils.closeQuietly(fsDataOutputStream);
    fs.close();
}

伪装权限

要测试通过javaAPI伪装成高级用户,来对自己没有权限的hdfs文件进行读写,需要先开启hdfs的权限验证。
开启hdfs的权限验证:
①关闭hdfs服务

cd hadoop所在目录
sbin/stop-dfs.sh

②在hdfs-site.xml中,修改如图位置的参数
hadoop离线阶段(第八节—1)通过JavaAPI操作hdfs
③把hdfs-site.xml发给其他机器

cd hadoop所在目录/etc/hadoop
scp hdfs-site.xml node02:$pwd
scp hdfs-site.xml node03:$pwd

④重启hdfs服务

cd hadoop所在目录
sbin/start-dfs.sh

然后通过通过javaAPI伪装成root用户来下载一个在hdfs上只有root用户有读写权限,其他用户无任何权限的文件

@Test
public void downHdfsFileByRoot() throws IOException, InterruptedException //伪装成root用户来下载hdfs上自己没有权限的文件
{
    //通过newInstance来伪装成root用户
    FileSystem fs=
            FileSystem.newInstance(URI.create("hdfs://node01:8020"),
                    new Configuration());
    //config_of_hadoop/core-site.xml是事先准备的使用 chmod 600 改过权限的文件
    fs.copyToLocalFile(new Path("hdfs://node01:8020/config_of_hadoop/core-site.xml"),
            new Path("E://core-site.xml"));
    fs.close();
}

将本地小文件合并到hdfs的一个文件中

@Test
public void mergeSmallFileToHdfs() throws IOException, InterruptedException //将本地小文件合并后上传到hdfs
{
   //创建一个hdfs客户端实例
   FileSystem hdfs=
           FileSystem.newInstance(URI.create("hdfs://node01:8020"),
                   new Configuration());
   //在hdfs文件系统创建一个输出流,来接收数据
   FSDataOutputStream outputStream=
           hdfs.create(new Path("hdfs://node01:8020/javatest/mytest/merge.txt"));

   //创建一个本地文件系统客户端实例
   FileSystem local=FileSystem.newInstanceLocal(new Configuration());

   //在本地文件系统的指定目录中遍历文件,将path存到迭代器中
   RemoteIterator<LocatedFileStatus> remoteIterator=
           local.listFiles(new Path("E://IDEA-Projects//BaiShi//" +
                   "learnHadoopoffLine//bigDataTest//src//test"),true);

   //遍历迭代器,得到文件path,使用本地文件系统的实例的open方法,将path转为输入流,并循环写入hdfs的输出流
   while (remoteIterator.hasNext())
   {
       Path path=remoteIterator.next().getPath();
       FSDataInputStream inputStream=local.open(path);
       IOUtils.copy(inputStream,outputStream);
       //及时关闭输入流
       IOUtils.closeQuietly(inputStream);
   }
   //写完文件后关闭输出流
   IOUtils.closeQuietly(outputStream);
   //关闭本地文件系统
   local.close();
   //关闭hdfs文件系统
   hdfs.close();
}

这个方法的思想是先在hdfs创建一个输出流,用来作为接收数据的容器,然后通过FileSystem获取文件某个目录下所有文件的迭代器,通过遍历迭代器把本地文件转为输入流,并传入到容器中。

标签:

未经允许不得转载:作者:1300-黄同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《hadoop离线阶段(第八节—1)通过JavaAPI操作hdfs》 发布于2020-11-10

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录