《Hadoop MapReduce实战手册》一2.9 使用HDFS的C API(libhdfs)

    xiaoxiao2024-04-17  9

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

    2.9 使用HDFS的C API(libhdfs)

    Hadoop MapReduce实战手册libhdfs是一个原生共享库,提供了一套C API,允许非Java程序与HDFS进行交互。libhdfs使用JNI通过Java与HDFS进行交互。

    准备工作目前的Hadoop发行版中包含了为32位和64位Linux操作系统预编译的libhdfs库。如果你的操作系统与预编译库不兼容,则可能需要下载Hadoop的标准发行版并从源代码编译libhdfs库。有关编译libhdfs库的信息请参见2.10节。

    操作步骤下列步骤显示了如何在HDFS环境下使用HDFS的C API执行操作。

    下面的示例程序会在HDFS中创建一个新文件,向新建文件中写入一些文本信息,并从HDFS读回该文件。用HDFS集群中NameNode的相关值替换NAMENODE_HOSTNAME和端口变量。该hdfs_cpp_demo.c源文件中的源代码包位于该文件夹的HDFS_C_API目录中。 #include "hdfs.h" int main(intargc, char **argv) { hdfsFSfs =hdfsConnect( "NAMENODE_HOSTNAME,PORT"); if (!fs) {      fprintf(stderr, "Cannot connect to HDFS.\n");      exit(-1);   } char* fileName = "demo_c.txt"; char* message = "Welcome to HDFS C API!!!"; int size = strlen(message); int exists = hdfsExists(fs, fileName); if (exists > -1) {    fprintf(stdout, "File %s exists!\n", fileName); }else{  // Create and open file for writing  hdfsFileoutFile = hdfsOpenFile(fs, fileName, O_WRONLY|O_CREAT, 0, 0, 0); if (!outFile) {  fprintf(stderr, "Failed to open %s for writing!\n", fileName);        exit(-2);   }   // write to file hdfsWrite(fs, outFile, (void*)message, size);   hdfsCloseFile(fs, outFile);   }   // Open file for reading hdfsFileinFile = hdfsOpenFile(fs, fileName, O_RDONLY, 0, 0, 0);   if (!inFile) { fprintf(stderr, "Failed to open %s for reading!\n", fileName);      exit(-2);   }   char* data = malloc(sizeof(char) * size);   // Read from file. tSizereadSize = hdfsRead(fs, inFile, (void*)data, size); fprintf(stdout, "%s\n", data);   free(data); hdfsCloseFile(fs, inFile); hdfsDisconnect(fs);   return 0; } 通过使用如下gcc命令编译上面的程序。当编译时,需要链接libhdfs和JVM库。因此,还必须包括Java安装路径的JNI头文件。一个示例编译命令如下所示。将ARCH和架构依赖的路径替换成当前系统的路径。 >gcchdfs_cpp_demo.c \ -I $HADOOP_HOME/src/c++/libhdfs \ -I $JAVA_HOME/include \ -I $JAVA_HOME/include/linux/ \ -L $HADOOP_HOME/c++/ARCH/lib/ \ -L $JAVA_HOME/jre/lib/ARCH/server\ -l hdfs -ljvm -o hdfs_cpp_demo 重置环境变量CLASSPATH,将其指向Hadoop的依赖环境。一种保险的方法是将$HADOOP_HOME和$HADOOP_HOME/lib中的所有jar文件全部包括在环境变量中。 export CLASSPATH=$HADOOP_HOME/hadoop-core-xx.jar:...

    Ant构建脚本生成类路径

    在2.8节步骤2中给出的build文件的末尾,添加下面的Anttarget。本章源码包的HDFS_C_API文件夹中提供了修改后的build.xml脚本。

    <target name="print-cp">    <property name="classpath"`      refid="hadoop-classpath"/>`    <echo message="classpath= ${classpath}"/>` </target>`

    用ant print-cp执行Ant构建,之后会生成一个包含$HADOOP_HOME和$HADOOP_HOME/lib中的所有jar文件名的字符串。复制这个字符串导出到CLASSPATH环境变量中。

    执行程序。 >LD_LIBRARY_PATH=$HADOOP_HOME/c++/ARCH/lib:$JAVA_HOME/jre/lib/ARCH/ server./hdfs_cpp_demo Welcome to HDFS C API!!!

    工作原理首先,我们通过hdfsConnect命令输入NameNode的主机名(或IP地址)和端口来连接到一个HDFS集群。hdfsConnectAsUser命令可以作为一个特定的用户连接到一个HDFS集群。

    hdfsFSfs =hdfsConnect("NAMENODE_HOSTNAME",PORT);

    使用hdfsOpenFile命令新建文件,并获得新新建文件的句柄。O_WRONLY | O_CREAT标志表示新建一个文件或重写现有文件,并用只写模式打开它。其他支持的标志还有O_RDONLY和O_APPEND。该hdfsOpenFile命令的第四、第五和第六个参数分别表示进行读/写操作的缓冲区大小、块的冗余因子和新创建文件的块大小。如果想使用这三个参数的默认值,可以将它们指定为0。

    hdfsFileoutFile = hdfsOpenFile(fs, fileName,flags, 0, 0, 0);

    该hdfsWrite指令将提供的数据写入到outFile句柄指定的文件中。数据大小需要以字节数为单位指定。

    hdfsWrite(fs, outFile, (void*)message, size);

    hdfsRead命令从inFile指定的文件中读取数据。需要提供以字节为单位的缓冲区大小作为第四个参数。hdfsRead命令返回文件读取的实际字节数,该数量可能小于缓冲区大小。如果想要确保从文件中读取一定的字节数,最好是在循环内使用hdfsRead命令,直到读完了指定的字节数为止。

    char* data = malloc(sizeof(char) * size); tSizereadSize = hdfsRead(fs, inFile, (void*)data, size);

    更多参考HDFS的C API(libhdfs)支持的文件系统操作比前面示例中用到的多。请参见$HADOOP_HOME/src/c++/libhdfs/hdfs.h头文件获得更多有关的详细信息。

    使用HDFS的配置文件配置还可以使用HDFS的配置文件来告诉libhdfsNameNode的主机名和端口号,而不是通过hdfs-Connect命令以参数的方式传入。

    在hdfsConnect命令中,将NameNode的主机名和端口号改为"default"和0。(将主机名设置为NULL将使libhdfs使用本地文件系统)。 hdfsFSfs = hdfsConnect("default",0); 将HDFS安装的conf目录添加到CLASSPATH环境变量中。 export CLASSPATH=$HADOOP_HOME/hadoop-core-xx.jar:...:$HADOOP_HOME/conf
    最新回复(0)