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

    xiaoxiao2024-04-18  6

    本节书摘来异步社区《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程序执行文件系统操作。

    下面的示例程序会在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();  } } 将上面的程序编译并打包成一个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> 可以在Hadoop上使用以下命令执行上述示例。使用hadoop脚本运行示例,可以确保它采用了当前配置的HDFS,并从Hadoop的类路径中加载了必要的依赖。 >bin/hadoop jar HDFSJavaAPI.jar HDFSJavaAPIDemo hdfs://yourhost:9000

    Welcome to HDFS Java API!!!

    使用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());
    最新回复(0)