在大数据生态中,HDFS(Hadoop Distributed File System)是数据存储的核心组件。实际开发中,常需通过 Java API 操作 HDFS(如创建文件、上传数据),并通过 Shell 脚本简化执行流程。本文将详解 HDFS Java API 创建文件的核心逻辑、环境配置、完整代码,以及 Shell 脚本封装方案,帮助开发者快速落地 HDFS 文件操作需求。

一、核心原理与环境准备

1. 核心逻辑

HDFS Java API 创建文件的核心流程:

关键要点:

  • Configuration:加载 HDFS 配置(如 NameNode 地址);
  • FileSystem:HDFS 文件系统操作核心类,需通过FileSystem.get()获取实例;
  • FSDataOutputStream:HDFS 文件输出流,用于写入数据。

2. 环境准备

工具 / 依赖

版本要求

作用描述

Java

8+

核心开发语言

Hadoop

3.x(示例:3.3.4)

HDFS 核心依赖,提供 Java API

Maven

3.6+

依赖管理工具

集群环境

本地 Hadoop / 远程集群

需确保 HDFS 服务正常运行

3. 依赖配置(pom.xml)

需引入 Hadoop 核心依赖(HDFS API 包含在hadoop-hdfs-client中):


<dependencies>

<!-- Hadoop 核心依赖 -->

<dependency>

<groupId>org.apache.hadoop</groupId>

<artifactId>hadoop-common</artifactId>

<version>3.3.4</version>

</dependency>

<!-- HDFS Client 依赖(包含创建文件API) -->

<dependency>

<groupId>org.apache.hadoop</groupId>

<artifactId>hadoop-hdfs-client</artifactId>

<version>3.3.4</version>

</dependency>

<!-- 日志依赖 -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

<version>1.7.36</version>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-simple</artifactId>

<version>1.7.36</version>

<scope>runtime</scope>

</dependency>

</dependencies>

二、Java API 创建 HDFS 文件核心代码

Java 代码实现 “连接 HDFS→创建文件→写入内容→关闭资源” 全流程,代码仅 40 余行,支持本地 / 远程 HDFS 集群:


import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FSDataOutputStream;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IOUtils;

import java.io.ByteArrayInputStream;

import java.io.InputStream;

import java.net.URI;

public class HdfsFileCreator {

// HDFS 核心配置(根据实际集群修改)

private static final String HDFS_URI = "hdfs://localhost:9000"; // NameNode地址

private static final String HDFS_USER = "hadoop"; // HDFS操作用户(需与集群用户一致)

public static void main(String[] args) {

// 入参校验(接收2个参数:HDFS文件路径、文件内容)

if (args.length != 2) {

System.err.println("用法:java HdfsFileCreator <HDFS文件路径> <文件内容>");

System.exit(1);

}

String hdfsFilePath = args[0]; // 示例:/user/hadoop/test.txt

String fileContent = args[1]; // 示例:"Hello HDFS from Java API"

Configuration conf = new Configuration();

FileSystem fs = null;

InputStream in = null;

FSDataOutputStream out = null;

try {

// 1. 配置HDFS URI

conf.set("fs.defaultFS", HDFS_URI);

// 2. 获取FileSystem实例(指定用户,避免权限问题)

fs = FileSystem.get(new URI(HDFS_URI), conf, HDFS_USER);

// 3. 构造HDFS文件路径

Path path = new Path(hdfsFilePath);

// 4. 检查文件是否已存在,存在则删除(可选,根据需求调整)

if (fs.exists(path)) {

System.out.println("文件已存在,删除旧文件:" + hdfsFilePath);

fs.delete(path, false); // false:不递归删除(仅删除文件)

}

// 5. 创建文件并获取输出流

out = fs.create(path);

// 6. 写入文件内容(将字符串转为输入流)

in = new ByteArrayInputStream(fileContent.getBytes("UTF-8"));

// 7. 拷贝数据(IOUtils为Hadoop工具类,自动处理流)

IOUtils.copyBytes(in, out, conf);

System.out.println("HDFS文件创建成功!路径:" + hdfsFilePath);

} catch (Exception e) {

System.err.println("HDFS文件创建失败:" + e.getMessage());

e.printStackTrace();

System.exit(1);

} finally {

// 8. 关闭资源(避免泄漏)

IOUtils.closeStream(in);

IOUtils.closeStream(out);

try {

if (fs != null) fs.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

关键代码说明

  1. 配置与权限
    • HDFS_URI:NameNode 地址(本地集群默认hdfs://localhost:9000,远程集群替换为hdfs://namenode-ip:9000);
    • HDFS_USER:需指定 HDFS 集群的有效用户(如hadoop),避免权限拒绝(Permission denied)。
  1. 文件创建:fs.create(path) 用于创建新文件,返回FSDataOutputStream流;
  1. 资源关闭:使用 Hadoop 提供的IOUtils.closeStream()工具类,安全关闭流与FileSystem实例;
  1. 入参设计:支持通过命令行传入 HDFS 文件路径和内容,便于 Shell 脚本调用。

三、Shell 脚本封装执行(一键运行)

为简化执行流程,编写 Shell 脚本封装 “编译→打包→运行” 全步骤,无需手动执行复杂命令:

1. Shell 脚本(create_hdfs_file.sh


#!/bin/bash

# 描述:HDFS文件创建脚本(封装Java程序执行)

# 用法:./create_hdfs_file.sh <HDFS文件路径> <文件内容>

# 检查入参

if [ $# -ne 2 ]; then

echo "用法错误!正确用法:"

echo "./create_hdfs_file.sh <HDFS文件路径> <文件内容>"

echo "示例:./create_hdfs_file.sh /user/hadoop/test.txt 'Hello HDFS'"

exit 1

fi

# 定义变量

HDFS_FILE_PATH=$1

FILE_CONTENT=$2

PROJECT_DIR=$(cd $(dirname $0); pwd) # 项目根目录

JAR_NAME="hdfs-file-creator-1.0.jar" # 打包后的JAR文件名

MAIN_CLASS="HdfsFileCreator" # 主类名

# 1. 编译Java代码(需确保当前目录为项目根目录,src/main/java为源码路径)

echo "开始编译Java代码..."

javac -cp $(hadoop classpath) -d $PROJECT_DIR/target/classes $PROJECT_DIR/src/main/java/HdfsFileCreator.java

# 2. 打包为JAR文件(无需Manifest,通过指定主类运行)

echo "开始打包JAR文件..."

jar -cvf $PROJECT_DIR/target/$JAR_NAME -C $PROJECT_DIR/target/classes .

# 3. 运行Java程序(通过hadoop jar命令执行,自动加载Hadoop依赖)

echo "开始创建HDFS文件:$HDFS_FILE_PATH"

hadoop jar $PROJECT_DIR/target/$JAR_NAME $MAIN_CLASS $HDFS_FILE_PATH "$FILE_CONTENT"

# 4. 检查执行结果

if [ $? -eq 0 ]; then

echo "文件创建成功!可通过以下命令验证:"

echo "hadoop fs -ls $(dirname $HDFS_FILE_PATH)" # 列出目录

echo "hadoop fs -cat $HDFS_FILE_PATH" # 查看文件内容

else

echo "文件创建失败!"

exit 1

fi

2. 脚本关键说明

  1. 依赖加载:使用hadoop classpath自动获取 Hadoop 所有依赖的类路径,避免手动配置复杂依赖;
  1. 编译打包
    • javac 编译 Java 代码,输出 class 文件到target/classes目录;
    • jar 命令打包 class 文件为 JAR(无需手动创建 Manifest 文件);
  1. 运行方式:通过hadoop jar命令运行 JAR 包,Hadoop 会自动加载自身依赖,避免类找不到(ClassNotFoundException);
  1. 结果验证:脚本执行成功后,自动提示验证命令(hadoop fs -ls/hadoop fs -cat)。

四、运行测试步骤(本地 Hadoop 示例)

1. 前提条件

  • 已配置JAVA_HOME和HADOOP_HOME环境变量(确保hadoop命令可全局执行)。

2. 测试步骤

(1)项目目录结构

确保项目目录结构如下(与 Shell 脚本适配):


hdfs-file-creator/

├── src/

│ └── main/

│ └── java/

│ └── HdfsFileCreator.java # Java核心代码

└── create_hdfs_file.sh # Shell脚本

(2)赋予脚本执行权限

chmod +x create_hdfs_file.sh

(3)执行脚本创建 HDFS 文件

./create_hdfs_file.sh /user/hadoop/test.txt "Hello HDFS from Shell + Java API"

(4)验证结果

脚本执行成功后,输出如下信息:


开始编译Java代码...

开始打包JAR文件...

开始创建HDFS文件:/user/hadoop/test.txt

HDFS文件创建成功!路径:/user/hadoop/test.txt

文件创建成功!可通过以下命令验证:

hadoop fs -ls /user/hadoop

hadoop fs -cat /user/hadoop/test.txt

执行验证命令,确认文件存在且内容正确:


# 查看文件是否存在

hadoop fs -ls /user/hadoop

# 查看文件内容

hadoop fs -cat /user/hadoop/test.txt

五、避坑指南与常见问题解决

1. 权限问题(Permission denied)

  • 原因:HDFS_USER配置错误,或执行用户无 HDFS 目录写入权限;
  • 解决
    1. 确认HDFS_USER为集群有效用户(如hadoop);
    1. 给 HDFS 目录授权:hadoop fs -chmod 777 /user/hadoop(测试环境,生产环境谨慎使用)。

2. 连接超时(Connection refused)

  • 原因:NameNode 地址错误,或 HDFS 服务未启动;
  • 解决
    1. 检查HDFS_URI是否正确(远程集群需确保 NameNode IP 可访问);
    1. 启动 HDFS 服务:start-dfs.sh

3. 类找不到(ClassNotFoundException)

  • 原因:未加载 Hadoop 依赖,或 JAR 包打包错误;
  • 解决
    1. 编译时通过-cp $(hadoop classpath)加载依赖;
    1. 运行时使用hadoop jar命令,而非java -jar。

4. 中文乱码

  • 原因:文件内容包含中文时,编码不一致;
  • 解决:Java 代码中指定 UTF-8 编码(new ByteArrayInputStream(fileContent.getBytes("UTF-8")))。

六、进阶扩展与最佳实践

1. 功能扩展

  • 文件上传:修改 Java 代码,支持从本地文件上传到 HDFS(将ByteArrayInputStream替换为FileInputStream);
  • 批量创建:扩展 Shell 脚本,支持从配置文件读取多个文件路径和内容,批量创建;
  • 权限设置:创建文件时指定权限(如fs.create(path, (short) 0644)),0644 表示所有者可读可写,其他用户可读。

2. 生产环境最佳实践

  • 配置分离:将HDFS_URI、HDFS_USER等配置抽离为配置文件(如hdfs-config.properties),避免硬编码;
  • 日志输出:集成 Logback/Log4j,将运行日志输出到文件,便于问题排查;
  • 异常重试:添加重试机制(如网络波动导致创建失败时,重试 3 次);
  • 安全认证:若 HDFS 集群开启 Kerberos 认证,需在Configuration中添加 Kerberos 配置(如krb5.conf路径、认证票据)。

总结

本文通过 “Java API 核心实现 + Shell 脚本封装”,提供了一套轻量、可落地的 HDFS 文件创建方案:

  1. Java 代码简洁高效(40 余行),覆盖连接、创建、写入、资源释放全流程,支持本地 / 远程集群;
  1. Shell 脚本一键运行,封装编译、打包、执行步骤,降低使用门槛;
  1. 解决了权限、依赖、编码等常见问题,可直接应用于开发 / 测试环境。

该方案适用于大数据场景中 HDFS 文件的自动化创建需求(如定时任务、数据导入前置步骤),如需扩展其他 HDFS 操作(如删除、重命名、上传文件夹),可基于本文代码框架快速迭代。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐