hdfs的API操作

14 篇文章 0 订阅
4 篇文章 0 订阅

目录

hdfsAPI操作环境配置

api操作获取FileSystem

api操作,功能型

 api上传和下载

 api访问权限控制

api小文件合并

下一篇:hdfs高可用和联邦机制


hdfsAPI操作环境配置

一、准备工作

1、配置Windows的hadoop运行环境,否则运行代码会出现

缺少winutils.exe、hadoop.dll

这两个文件可以在github上找

貌似hadoop2.10.1不用配置环境也可以使用api

第一步:将这两个文件放到一个全英文没空格的文件夹下

例如:D:\English_path\hadoop
第二步:配置环境变量:HADOOP_HOME并将%HADOOP_HOME%\bin添加到path

这两个文件是放在bin下的所以要\bin

第三步:把hadoop.dll文件拷贝放入C:\Windows\System32

2、导入Maven依赖

找jar包可以在百度中搜mvn进入官方依赖库

在这里搜

导入这些依赖

 <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
	    <!--打包插件-->
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
        </dependency>
    </dependencies>

一些插件
<build>
        <!--编译插件-->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </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>

api操作获取FileSystem

一、使用url方式访问数据(了解,用的不多)

上传一个a.txt做测试

//通过URL来访问数据,实现一个拷贝功能

    @Test

    public void test1() throws Exception {

        //1、注册hdfsurl

        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());

        //2、获取文件输入流

        InputStream inputStream = new URL("hdfs://node01:8020/a.txt").openStream();

        //3、获取文件输出流

        FileOutputStream outputStream = new FileOutputStream(new File("D:\\code\\java_code\\HadoopTest\\src\\hello.txt"));

        //4、实现文件的拷贝,IOUtils.copy实现文件拷贝,这个工具类一定要导这个包org.apache.commons.io.IOUtils

        IOUtils.copy(inputStream,outputStream);

        //5、关闭流

        IOUtils.closeQuietly(inputStream);

        IOUtils.closeQuietly(outputStream);

    }

执行后,发现已经拷贝过来了

 

补充:清除烦人的log4j警告

在resources下创建一个log4j.properties

并写入,现在不需要知道怎么写

log4j.rootLogger=info,appender

log4j.appender.appender=org.apache.log4j.ConsoleAppender

log4j.appender.appender.layout=org.apache.log4j.TTCCLayout

log4j的警告就没了

注:这个警告是jdk版本太高,1.8就没这个警告了

 

 

二、使用文件系统方式访问(重点)

主要涉及一下class

1、Configuration,该类的对象封装了客户端或者服务器的配置

2、FileSystem,该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象

get方法从conf中的第一个参数fs.defaultFS的配置值判断具体是什么类

如果代码中没有指定fs.defaultFS,并且工程ClassPath下也没有给定相应的配置,conf中的默认值就来自于Hadoop的Jar包中的core-defalut.xml

默认值为file:///则获取的不是第一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象

 

1、获取FileSystem的几种方式

 //第一种获得FileSystem的方法

    @Test

    public void getFileSystem1() throws Exception {

        //1、创建Configuration对象

        Configuration configuration = new Configuration();

        //2、指定我们使用的文件系统类型

        configuration.set("fs.defaultFS","hdfs://node01:8020/");

        //3、获取指定的文件系统

        FileSystem fileSystem = FileSystem.get(configuration);

        //4、输出

        System.out.println(fileSystem);

    }

    //第二种获得FileSystem的方法

    @Test

    public void getFileSystem2() throws Exception{

        //URI是统一路径标识符

        //这种方式更简单用的是get的重载方法,要new两个对象:URI、Configuration

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        System.out.println("fileSystem:"+fileSystem);

    }

    //第三种获得FileSystem的方法

    @Test

    public void getFileSystem3() throws Exception{

        Configuration configuration = new Configuration();

        configuration.set("fs.defaultFS","hdfs://node01:8020/");

        //就是将第一种方式的get改成了newInstance

        FileSystem fileSystem = FileSystem.newInstance(configuration);

        System.out.println(fileSystem);

    }

    //第四种获得FileSystem的方法

    @Test

    public void getFileSystem4() throws Exception{

        //还是newInstance的重载方法

        FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://node01:8020"),new Configuration());

        System.out.println(fileSystem);

    }

api操作,功能型

一、遍历HDFS中所有文件

    @Test

    public void listMyFiles()throws Exception{

        //1、获取FileSystem

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        //2、获取RemoteIterator得到所有的文件或文件夹,第一个参数指定遍历的路径,第二个参数表示是否要递归遍历

        RemoteIterator<LocatedFileStatus> Iterator = fileSystem.listFiles(new Path("/"), true);

        //3、循环遍历

        while (Iterator.hasNext()){

            LocatedFileStatus fileStatus = Iterator.next();

            //获取路径并打印

           //这里可以用fileStatus获取很多东西路径、文件名、分块等 System.out.println(fileStatus.getPath()+"---"+fileStatus.getPath().getName());

            BlockLocation[] blockLocations = fileStatus.getBlockLocations();

            System.out.println("block数"+blockLocations.length);

        }

        //4、关闭文件系统

        fileSystem.close();

    }

结果:

 

二、在HDFS上创建文件夹

 @Test

    public void mkdirs()throws Exception{

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        //FS调用mkdirs就可以了,这个方法可以递归创建

        boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));

        if (mkdirs) System.out.println("创建成功");

        fileSystem.close();

    }

执行后:

hdfs中就有了这个文件夹

 

三、创建文件

//这个方法可以创建文件,且是递归创建

        fileSystem.create(new Path("/hello/mydir/test/a.txt"));

创建成功

 api上传和下载

一、下载文件

    @Test

    public void downloadFile()throws Exception{

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        //1、获取文件输入流

        FSDataInputStream inputStream = fileSystem.open(new Path("/a.txt"));

        //2、获取文件输出流

        FileOutputStream outputStream = new FileOutputStream(new File("src/hello.txt"));

        //3、文件的拷贝

        IOUtils.copy(inputStream,outputStream);

        //4、关闭流

        IOUtils.closeQuietly(inputStream);

        IOUtils.closeQuietly(outputStream);

        fileSystem.close();

    }

 

//更简便的方法,文件下载方式2

    @Test

    public void downloadFile2()throws Exception{

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        //调用copyToLocalFile,里面还有很多方法例如上传

        fileSystem.copyToLocalFile(new Path("/a.txt"),new Path("src/hello.txt"));

        fileSystem.close();

    }

 

二、上传文件

 @Test

    public void putData()throws Exception{

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

        //调用copyFromLocalFile方法上传

        //注意这里在这个文件改动后上传hdfs的crc校验会导致报错,改个名或者去删crc文件

        fileSystem.copyFromLocalFile(new Path("src/a.txt"),new Path("/"));

        fileSystem.close();

    }

 api访问权限控制

一、测试

因为在hdfs-site.xml中关闭了访问权限

所以rw没有任何意义

 

现在我们测试一下

修改a.txt的权限全部关闭

hdfs dfs -chmod 000 /a.txt

我们执行之前写好的文件下载方法

发现下载成功了,说明权限毫无作用

 

我们现在开启权限

先停止hdfs

stop-dfs.sh

在修改配置文件为true

在分发给其他机器

scp hdfs-site.xml node02:$PWD

再启动hdfs

 

网页上下载a.txt就不允许了

api写的也报错了

 

现在加一个当前用户可读可写的权限

hdfs dfs -chmod 600 /a.txt

发现还是读不了,因为a.txt是所属root,windows的用户属于其他用户

权限改为666就可以读了

 

二、不是所属用户,想访问这个文件,要用到一个技术:伪装用户

使用get的重载方法

get(final URI uri, final Configuration conf, String user)

这里这个user,就是设置以什么用户去访问

FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");

发现伪造用户后就可以以root身份访问了

api小文件合并

命令行下的合并

第一种:

该命令可以将很多的hdfs文件合并为一个大的文件下载到本地

hdfs dfs -getmerge /config/*.xml   ./hello.xml

*指的是这里所有的xml文件

我们用txt文件演示

hdfs dfs -getmerge /a.txt /hello.txt ./big.txt

合并成功

 

第二种(用的较多):

在上传的时候将小文件合并成一个大文件

要用到java程序

代码:

@Test

    public void mergeFile()throws Exception{

        //这里由于之前设置了权限,使用伪装root,初学阶段还是改成无权限的好

        FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");

        //1、得到一个大文件的输出流

        FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.txt"));

        //2、获取一个本地的文件系统(可以访问本地磁盘)

        LocalFileSystem local = FileSystem.getLocal(new Configuration());

        //3、通过本地文件系统获取文件列表,为一个集合

        FileStatus[] fileStatuses = local.listStatus(new Path("src/input"));

        //循环输入

        for (FileStatus fileStatus : fileStatuses) {

            //4、获取输入流

            FSDataInputStream inputStream = local.open(fileStatus.getPath());

            //5、将小文件的数据复制到大文件

            IOUtils.copy(inputStream,outputStream);

        }

        //6、释放资源

        IOUtils.closeQuietly(outputStream);

        local.close();

        fileSystem.close();

    }

从网页上下载下来查看

发现合并成功

 

合并后只占一个元数据空间,减轻了NameNode的压力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值