《Hadoop MapReduce实战手册》一2.8 使用HDFS的Java API

本节书摘来异步社区《Hadoop MapReduce实战手册》一书中的第2章,第2.8节,作者: 【美】Srinath Perera , Thilina Gunarathne 译者: 杨卓荦 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.8 使用HDFS的Java API

Hadoop MapReduce实战手册
HDFS Java API可用于任何Java程序与HDFS交互。该API使我们能够从其他Java程序中利用到存储在HDFS中的数据,也能够使用其他非Hadoop的计算框架处理该数据。有时,可能也会遇到要直接从MapReduce应用程序中访问HDFS的用例。但是,如果你是在HDFS中直接通过map或reduce任务写入或修改文件,那么你要知道,这样做实际上违反了MapReduce构架的无副作用的本质,可能会导致某些用例出现数据一致性问题。

准备工作
设置HADOOP_HOME环境变量指向Hadoop的安装根目录。

操作步骤
下列步骤显示了如何使用HDFS的Java API来对HDFS集群使用Java程序执行文件系统操作。

  1. 下面的示例程序会在HDFS中创建一个新文件,写一些文本内容到新建文件,并从HDFS中读回该文件:
importjava.io.IOException;

importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.FSDataInputStream;
importorg.apache.hadoop.fs.FSDataOutputStream;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.fs.Path;

public class HDFSJavaAPIDemo {

  public static void main(String[] args) throws IOException {
   Configuration conf = new Configuration();
   FileSystemfs = FileSystem.get(conf);
   System.out.println(fs.getUri());
   Path file = new Path("demo.txt");

   if (fs.exists(file)) {
   System.out.println("File exists.");
   } else {
    // Writing to file
    FSDataOutputStreamoutStream = fs.create(file);
    outStream.writeUTF("Welcome to HDFS Java API!!!");
    outStream.close();
   }

   // Reading from file
   FSDataInputStreaminStream = fs.open(file);
   String data = inStream.readUTF();
   System.out.println(data);
   inStream.close();

   fs.close();
 }
}
  1. 将上面的程序编译并打包成一个JAR包。解压本章提供的源码包,转到HDFS_Java_API文件夹,然后运行Ant构建即可。HDFSJavaAPI.jar文件将在build文件夹中被创建。
>cd HDFS_java_API
>ant

可以使用下面的Ant构建文件来编译上面的示例程序:

<project name="HDFSJavaAPI" default="compile" basedir=".">
  <property name="build" location="build"/>
  <property environment="env"/>

  <path id="hadoop-classpath">
   <filesetdir="${env.HADOOP_HOME}/lib">
     <include name="**/*.jar"/>
   </fileset>
   <filesetdir="${env.HADOOP_HOME}">
     <include name="**/*.jar"/>
   </fileset>
  </path>

  <target name="compile">
   <mkdirdir="${build}"/>
   <javacsrcdir="src" destdir="${build}">
     <classpathrefid="hadoop-classpath"/>
   </javac>
   <jar jarfile="HDFSJavaAPI.jar" basedir="${build}"/>
   </target>

  <target name="clean">
   <delete dir="${build}"/>
  </target>
</project>
  1. 可以在Hadoop上使用以下命令执行上述示例。使用hadoop脚本运行示例,可以确保它采用了当前配置的HDFS,并从Hadoop的类路径中加载了必要的依赖。
>bin/hadoop jar HDFSJavaAPI.jar HDFSJavaAPIDemo
hdfs://yourhost:9000

Welcome to HDFS Java API!!!

  1. 使用ls命令列出新创建的文件:
>/bin/hadoopfs -ls
Found 1 items
-rw-r--r-- 3 foosupergroup     20 2012-04-27 16:57 /user/
foo/demo.txt

工作原理
为了以编程方式与HDFS进行交互,首先需要得到当前配置文件系统的句柄。实例化一个Configuration对象,并获得一个Hadoop环境中的FileSystem句柄,它将指向当前环境的HDFS NameNode。有几种替代配置FileSystem对象的方法,将在本节的“更多参考”中的“配置文件系统对象”中讨论。

Configuration conf = new Configuration();
FileSystemfs = FileSystem.get(conf);

FileSystem.create(filePath)方法会在指定的路径创建一个新的文件,并提供一个到新创建的文件的FSDataOutputStream对象。FSDataOutputStream封装了java.io.DataOutputStream,并允许程序向文件中写入基本Java数据类型。如果该文件存在,FileSystem.Create()方法将覆盖该文件。在这个例子中,该文件将在HDFS中相对于用户的主目录进行创建,产生类似/user//demo.txt的路径。

Path file = new Path("demo.txt");
FSDataOutputStreamoutStream = fs.create(file);
outStream.writeUTF("Welcome to HDFS Java API!!!");
outStream.close();

FileSystem.open(filePath)打开给定文件的FSDataInputStream。FSDataInputStream封装了java.io.DataInputStream,允许程序从文件中读取基本Java数据类型。

FSDataInputStreaminStream = fs.open(file);
String data = inStream.readUTF();
System.out.println(data);
inStream.close();

更多参考
HDFS的Java API支持的文件系统操作比我们在上面的示例中用到的多得多。完整的API文档可以在
http://hadoop.apache.org/common/docs/current/api/org/apache/hadoop/fs/FileSystem.html找到。

配置文件系统对象
我们也可以在Hadoop的环境之外使用HDFS的Java API。当这样做时,必须显式配置HDFS的NameNode和端口。以下是几种进行该项配置的方法。

可以通过如下方式在获得FileSystem对象之前加载Configuration对象的配置文件。但需要确保将所有的Hadoop和依赖库都添加到类路径中。

Configuration conf = new Configuration(); 
  conf.addResource(new Path("..._/hadoop/conf/core-site.xml_"));
  conf.addResource(new Path("..._/hadoop/conf/hdfs-site.xml_"));

  FileSystemfileSystem = FileSystem.get(conf);

还可以通过如下方式指定NameNode和端口。将NAMENODE_HOSTNAME和PORT替换为HDFS安装的NameNode的主机名和端口。

Configuration conf = new Configuration();
  conf.set("fs.default.name", "hdfs://NAMENODE_HOSTNAME:PORT");
  FileSystemfileSystem = FileSystem.get(conf);

HDFS的文件系统API,是一种支持多个文件系统的抽象。如果上述程序无法找到有效的HDFS配置,它将会指向本地文件系统,而不是HDFS。可以通过如下方式使用getUri()函数识别FileSystem对象的当前文件系统。在使用正确的HDFS配置文件的情况下,会返回hdfs://your_namenode:port,在使用本地文件系统的情况下,则会返回file:///。

fileSystem.getUri();

获取文件的数据块列表
FileSystem对象的getFileBlockLocations()函数,可以用来获取存储在HDFS中的文件数据块的列表,同时也可以获取存储块的主机名和块的偏移量。如果计划使用Hadoop MapReduce之外的其他框架来执行文件数据的任何数据本地化操作,那么这些信息将会非常有用。

FileStatusfileStatus = fs.getFileStatus(file);
BlockLocation[] blocks = fs.getFileBlockLocations(
     fileStatus, 0, fileStatus.getLen());
    原文作者:MapReduce
    原文地址: https://yq.aliyun.com/articles/97935
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞