HDFS Java API 位于 org.apache.hadoop.fs 包中,这些API能够支持的操作包括打开文件、读写文件、删除文件等。Hadoop类库中最终面向用户提供的接口类是FileSystem。该类是一个抽象类,只能通过get方法获取到具体的类。该类封装了大部分文件操作,如mkdirdelete等。 

<!--指定maven项目jdk编译版本,默认是jdk1.5-->
<properties>
  <maven.compiler.source>8</maven.compiler.source>
  <maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
  <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>2.7.3</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
  </dependency>
</dependencies>

HDFS Java API 的一般用法

HDFS Java API为客户端提供了针对文件系统、目录和文件的各种操作功能。在客户端应用程序中,通常按以下步骤来使用HDFS Java API。

实例化Configuration类 Configuration 类位于org.apache.hadoop.conf 包中,它封装了客户端或服务器的配置。每个配置选项是一个键/值对,通常以XML格式保存。

Configuration conf = new Configuration();

默认情况下,Configuration 的实例会自动加载HDFS的配置文件core-site.xml,从中获取Hadoop集群的配置信息。为了保证程序能够成功加载,一般放于项目根目录下。

实例化FileSystem类FileSystem类是客户端访问文件系统的入口,是Hadoop为客户端提供的一个抽象的文件系统。DistributedFileSystem类是FileSystem的一个具体实现,是HDFS真正的客户端API

FileSytem fs = FileSystem.get(uri, conf, user); //伪装用户操作文件系统

设置目标对象的路径:HDFS API提供Path类来封装HDFS文件路径。Path类位于org.apache.hadoop.fs包中。

Path path = new Path("/test");

执行文件或目录操作:得到FileSystem实例之后,就可以使用该实例提供的方法成员来执相应的操作,例如打开文件、创建文件、重名文件、删除文件或检测文件是否存在等。

返回值类型

方法名称及参数

功能说明

void

copyFromLocalFile(Path src, Path dsc)

从本地磁盘复制文件到HDFS

void

copyToLocalFile(Path src, Path dsc)

从HDFS复制文件到本地磁盘

abstract boolean

rename(Path src, Path dsc)

修改目录或文件名

boolean

delete(Path f,boolean)

删除指定文件

long

getLength(Path f)

返回文件长度

boolean

isDirectory(Path f)

指定文件是否为目录

boolean

isFile(Path f)

指定 path 是否为文件

boolean

mkdirs(Path f)

建立子目录

boolean

exists(Path f)

检查指定文件是否存在

long

getBlockSize(Path f)

返回指定文件的数据块大小

short

getDefaultReplication(Path f)

返回默认的副本系数

abstract FileStatus

getFileStatus(Path f)

返回指定文件的状态

void

moveFromLocalFile(Path[] src, Path dsc)

把本地文件迁移到HDFS

void

moveToLocalFile(Path src, Path dsc)

把HDFS文件迁移到本地磁盘

FSDataInputStream

open(Path f)

打开指定的文件

FSDataOutputStream

create(Path f)

创建一个文件

文件上传与下载

@Test
public void testUpload() throws Exception{
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(URI.create("hdfs://node:9000"), conf,"root");
    fs.copyFromLocalFile(new Path("E:\\大数据搭建环境工具\\《HIVE环境搭建1》.pdf"),new Path("/"));
    System.out.println("文件上传成功~");
}

@Test
public void hdfsDownLoad() throws Exception{
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(URI.create("hdfs://node:9000"), conf,"root");
    fs.copyToLocalFile(new Path("/《HIVE环境搭建1》.pdf"),new Path("E:\\test.pdf"));
    System.out.println("文件数据读取成功~");
}

文件读取

客户端将要读取的文件路径发送给NameNodeNameNode获取文件的元信息(主要是block的存放位置信息)返回给客户端,客户端根据返回的信息找到相应DatNode逐个获取文件的block并在客户端本地进行数据追加合并从而获得整个文件。

  1. HDFS 客户端通过DistributedFileSystem 对象的open()方法打开要读取的文件。
  2. DistributedFileSystem负责向远程的名称节点NameNode发起RPC调用,得到文件的数据块信息,返回数据块列表。对于每个数据块,NameNode返回该数据块的DataNode地址
  3. DistributedFileSystem返回一个FSDataInputStream对象给客户端,客户端调用FSDataInputStream对象的read()方法开始读取数据
  4. 通过对数据流反复调用read()方法,把数据从数据节点传输到客户端
  5. 当客户端读取完数据时,调用FSDataInputStream对象的close()方法关闭读取流。

返回值

方法名词及参数

说明

int

read(byte[] buf)

把数据读取到缓冲中。

void

seek(long offset)

指定输入流的第offset字节

readBoolean、readByte、readInt、readUTF、....

这些方法继承自 java.io.DataInputStream

@Test
public void hdfsReader() throws Exception{
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(URI.create("hdfs://node:9000"), conf,"root");
    Path path = new Path("/file/test2.txt");
    FSDataInputStream fis = fs.open(path);
    byte[] b = new byte[1024];
    int len = -1;
    while ((len=fis.read(b))!=-1){
        System.out.println(new String(b, 0, len));
    }

    System.out.println("文件数据读取成功~");
}

文件写入

客户端要向HDFS写数据,首先跟NameNode通信以确认可以写文件并获得接收文件BlockDataNode,然后客户端按顺序将文件逐个Block传递给相应DataNode,并由接收到BlockDataNode负责向其他DataNode复制Block副本默认情况下每个Block都有三个副本,HDFS 数据存储单元(Block)。

  1. HDSF客户端调用DistributedFileSystem 对象的create()方法创建一个文件写入流对象
  2. DistributedFileSystem 对象向远程的NameNode节点发起一次RPC调用,NameNode检查该文件是否已经存在,以及客户端是否有权限新建文件
  3. 客户端调用FSOutputStream对象的write()方法写数据,数据先被写入缓冲区,再被切分为一个个数据包。
  4. 每个数据包被发送到由NameNode节点分配的一组数据节点的一个节点上,在这组数据节点组成的管道上依次传输数据包
  5. 管道上的数据节点按反向顺序返回确认信息,最终由管道中的第一个数据节点将整条管道的确认信息发送给客户端
  6. 客户端完成写入,调用close()方法关闭文件写入流
  7. 通知NameNode文件写入成功

返回值

方法名称

说明

void

close()

关闭输出流

long

getPos()

获取输出流的当前位置

void

hflush()

清理客户端用户缓冲中的数据

void

hsync()

把客户端用户缓冲中的数据同步到磁盘之中

writeByte、writeChars、writeInt、writeUTF

这写方法继承自java.io.DataOutputStream

@Test
public void hdfsWriter() throws Exception{
    Configuration conf = new Configuration();
    FileSystem fs = FileSystem.get(URI.create("hdfs://node:9000"), conf,"root");
    Path path = new Path("/file/test2.txt");
    FSDataOutputStream fos = fs.create(path);
    fos.writeUTF("你好,我是客户端传递的数据1");
    fos.writeUTF("你好,我是客户端传递的数据2");
    fos.writeUTF("你好,我是客户端传递的数据3");
    fos.close();
    fs.close();
    System.out.println("文件数据写入成功~");
}

Permission denied: user=xx, access=WRITE, inode="/file/test.txt" :root:supergroup:drwxr-xr-x表示user=xx没有写入数据的权限,需要伪造用户或修改操作权限