本文为您介绍如何通过Java API接口方式进行HDFS的相关操作。

背景信息

HDFS初始化

在使用HDFS提供的API之前,需要先进行HDFS初始化操作。初始化HDFS时会加载HDFS的配置文件,HDFS使用到的配置文件主要为core-site.xmlhdfs-site.xml两个文件。

初始化代码样例如下。
 private void init() throws IOException {
   conf = new Configuration();
   // conf path for core-site.xml and hdfs-site.xml
   conf.addResource(new Path(PATH_TO_HDFS_SITE_XML));
   conf.addResource(new Path(PATH_TO_CORE_SITE_XML));
   fSystem = FileSystem.get(conf);
 }

在HDFS文件系统初始化之后,就可以调用HDFS提供的各种API进行开发。

创建目录

如果要在HDFS文件系统中创建目录,需要FileSystem实例的exists方法判断该目录是否已经存在:
  • 如果存在,则直接返回。
  • 如果不存在,则调用FileSystem实例的mkdirs方法创建该目录。
创建目录代码样例如下。
/**
 * create directory path
 *
 * @param dirPath
 * @return
 * @throws java.io.IOException
 */
private boolean createPath(final Path dirPath) throws IOException {
    if (!fSystem.exists(dirPath)) {
        fSystem.mkdirs(dirPath);
    }
    return true;
}

写文件

通过调用FileSystem实例的create方法获取写文件的输出流。通常获得输出流之后,可以直接对这个输出流进行写入操作,将内容写入HDFS的指定文件中。写完文件后,需要调用close方法关闭输出流。

写文件代码样例如下。
/**
 * 创建文件,写文件
 *
 * @throws java.io.IOException
 */
private void createAndWrite() throws IOException {
   final String content = "Hello HDFS!";
   FSDataOutputStream out = null;
   try {
       out = fSystem.create(new Path(DEST_PATH + File.separator + FILE_NAME));
       out.write(content.getBytes());
       out.hsync();
       LOG.info("success to write.");
   } finally {
    // make sure the stream is closed finally.
       out.close();
  }
}

追加文件内容

对于已经在HDFS中存在的文件,可以追加指定的内容,以增量的形式在该文件现有内容的后面追加。通过调用FileSystem实例的append方法获取追加写入的输出流。然后使用该输出流将待追加内容添加到HDFS的指定文件后面。追加完指定的内容后,需要调用close方法关闭输出流。
注意 需要确保待追加的文件已经存在,并且没有正在被写入内容,否则追加内容会失败抛出异常。
追加文件内容代码样例如下。
/**
 * 追加文件内容
 *
 * @throws java.io.IOException
 */
private void appendContents() throws IOException {
    final String content = "Hello Hello";
    FSDataOutputStream out = null;
    try {
        out = fSystem.append(new Path(DEST_PATH + File.separator + FILE_NAME));
        out.write(content.getBytes());
        out.hsync();
        LOG.info("success to append.");
    } finally {
        // make sure the stream is closed finally.
        out.close();
    }
}

读文件

读文件即为获取HDFS上某个指定文件的内容。通过调用FileSystem实例的open方法获取读取文件的输入流。然后使用该输入流读取HDFS的指定文件的内容。读完文件后,需要调用close方法关闭输入流。

读文件代码样例如下。
private void read() throws IOException {
    String strPath = DEST_PATH + File.separator + FILE_NAME;
    Path path = new Path(strPath);
    FSDataInputStream in = null;
    BufferedReader reader = null;
    StringBuffer strBuffer = new StringBuffer();
    try {
        in = fSystem.open(path);
        reader = new BufferedReader(new InputStreamReader(in));
        String sTempOneLine;
        // write file
        while ((sTempOneLine = reader.readLine()) != null) {
            strBuffer.append(sTempOneLine);
        }
        LOG.info("result is : " + strBuffer.toString());
        LOG.info("success to read.");
    } finally {
        // make sure the streams are closed finally.
        IOUtils.closeStream(reader);
        IOUtils.closeStream(in);
    }
}

删除目录

通过调用delete方法删除HDFS上某个指定目录。delete方法第二个参数代表是否递归删除目录下面的所有目录。如果该参数为false,而目录下还存在文件或者子目录,则删除目录操作会失败。
注意 待删除的目录会被直接删除,且无法恢复,因此,请谨慎使用删除目录操作。
删除目录代码样例如下。
private boolean deletePath(final Path dirPath) throws IOException {
    if (!fSystem.exists(dirPath)) {
        return false;
    }
    // fSystem.delete(dirPath, true);
    return fSystem.delete(dirPath, true);
}

删除文件

通过调用delete方法删除HDFS上某个指定文件。
注意 待删除的文件会被直接删除,且无法恢复,因此,请谨慎使用删除文件操作。
删除文件代码样例如下。
private void deleteFile() throws IOException {
    Path beDeletedPath = new Path(DEST_PATH + File.separator + FILE_NAME);
    if (fSystem.delete(beDeletedPath, true)) {
        LOG.info("success to delete the file " + DEST_PATH + File.separator + FILE_NAME);
    } else {
        LOG.warn("failed to delete the file " + DEST_PATH + File.separator + FILE_NAME);
    }
}

移动或重命名文件

对于HDFS来说,文件的重命名和移动是一个操作。调用FileSystem的rename方法对HDFS文件系统的文件进行重命名操作。
注意 rename方法的原文件必须存在,并且目标文件不能存在,否则重命名操作会失败。
移动或重命名文件代码样例如下。
private void renameFile() throws IOException {
    Path srcFilePath = new Path(SRC_PATH + File.separator + SRC_FILE_NAME);
    Path destFilePath = new Path(DEST_PATH + File.separator + DEST_FILE_NAME);
        fs.rename(new Path(srcFilePath), new Path(destFilePath));
}

移动或重命名目录

对于HDFS来说,目录的重命名和移动是一个操作。调用FileSystem的rename方法对HDFS文件系统的目录进行重命名操作。
注意 rename方法的原目录必须存在,并且目标目录不能存在,否则重命名操作会失败。
移动或重命名目录代码样例如下。
private void renameDir() throws IOException {
    Path srcDirPath = new Path(SRC_PATH + File.separator + SRC_DIR_NAME);
    Path destDirPath = new Path(DEST_PATH + File.separator + DEST_DIR_NAME);
        fs.rename(new Path(srcDirPath), new Path(destDirPath));
}