大数据实验二HDFS编程实践:Shell命令与Java API完整落地

发布时间:2026/10/6 11:07:48
大数据实验二HDFS编程实践:Shell命令与Java API完整落地 简介本资源为大数据课程实验二的HDFS编程实践完整实验报告面向正在学习Hadoop与分布式文件系统的高校学生及大数据入门开发者帮助读者理解HDFS在Hadoop体系结构中的角色并掌握Shell命令与Java API两类文件操作方式。资源包内含1个docx文档约323KB内容涵盖实验内容、实验目的、过程截图说明及总结心得具体涉及hdfs dfs -put、-get、-ls、-rm、-copyFromLocal等常用命令以及基于FileSystem类实现文件创建、写入、读取与删除的Java代码示例并配有IDEA与Maven环境搭建步骤。目前已有2910人学习下载适合需要参考实验报告结构、对照操作流程或查漏补缺的读者可快速把握HDFS编程实践的核心知识点与实验组织方式。1. 大数据实验二-HDFS编程实践从命令行到 Java API 的完整落地很多人做大数据实验二-HDFS编程实践时卡在的不是概念而是命令行敲得挺顺一写 Java API 就报错。这个实验的核心诉求其实很明确用 HDFS 的 Shell 命令完成文件上传下载再用 Java API 复现同样的读写流程最后理解 NameNode、DataNode 和 Client 之间到底怎么协作。它适合刚接触 Hadoop 的在校学生也适合需要快速补齐 HDFS 操作能力的后端工程师。我当年第一次做这个实验光FileSystem.get()返回 null 就折腾了一下午后来才发现是core-site.xml没放进 classpath。这篇笔记就按命令跑通 → API 复现 → 读写流程拆解 → 踩坑排查的顺序把 HDFS 编程实践讲透让你少走我走过的弯路。2. HDFS 常用命令与 Java API 环境搭建先把地基打牢2.1 HDFS Shell 命令的 6 个高频操作HDFS 编程实践的第一步不是写代码而是确认集群能正常读写。HDFS 常用命令的语法和 Linux 很像但前缀是hdfs dfs。下面这组命令覆盖了实验里 90% 的场景建议逐条敲一遍观察输出。# 查看 HDFS 根目录结构 hdfs dfs -ls / # 创建实验用目录-p 支持多级创建 hdfs dfs -mkdir -p /user/experiment/input # 从本地上传文件到 HDFS hdfs dfs -put ./local_data.txt /user/experiment/input/ # 查看 HDFS 上的文件内容 hdfs dfs -cat /user/experiment/input/local_data.txt # 下载 HDFS 文件到本地 hdfs dfs -get /user/experiment/input/local_data.txt ./downloaded.txt # 查看文件块信息验证副本数和块大小 hdfs fsck /user/experiment/input/local_data.txt -files -blocks逻辑说明-put和-get是最常用的上传下载命令-mkdir -p避免父目录不存在时报错。hdfs fsck是排查数据块问题的关键工具能显示每个块分布在哪些 DataNode 上。参数说明-put的源路径是本地文件系统目标路径是 HDFS-get反过来。如果目标路径已存在-put会直接覆盖不会提示这点要特别注意。-ls默认显示权限、副本数、所有者、大小和修改时间和 Linuxls -l类似。提示执行hdfs dfs命令前确保HADOOP_HOME已配置且sbin/start-dfs.sh已启动。用jps能看到 NameNode、DataNode、SecondaryNameNode 三个进程才算正常。2.2 Java API 环境搭建依赖与配置文件HDFS 编程实践的重头戏是 Java API。很多人卡在环境上其实核心就三件事引入依赖、放对配置文件、设置用户身份。!-- pom.xml 中引入 Hadoop 客户端依赖 -- dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-client/artifactId version3.3.4/version /dependency逻辑说明hadoop-client是聚合依赖包含了hadoop-common、hadoop-hdfs、hadoop-mapreduce-client-core等模块做 HDFS 编程实验引入这一个就够了。参数说明版本号要和集群的 Hadoop 版本一致否则可能出现 RPC 协议不兼容。如果你用的是 2.x 集群把 version 改成对应的 2.7.x 或 2.10.x。配置文件方面把集群的core-site.xml和hdfs-site.xml复制到项目的src/main/resources目录下。core-site.xml里的fs.defaultFS告诉客户端 NameNode 地址hdfs-site.xml里的dfs.replication决定副本数。如果这两个文件缺失FileSystem.get()会默认连本地文件系统这就是很多人代码没报错但文件没进 HDFS的根本原因。// 获取 FileSystem 对象的标准写法 Configuration conf new Configuration(); // 显式指定 NameNode 地址避免配置文件缺失时连到本地 conf.set(fs.defaultFS, hdfs://namenode-host:8020); // 设置操作用户避免权限拒绝 System.setProperty(HADOOP_USER_NAME, root); FileSystem fs FileSystem.get(conf);逻辑说明Configuration会按顺序加载 classpath 下的core-site.xml再用代码里的set覆盖。System.setProperty设置 HADOOP_USER_NAME 是绕过权限问题的常用手段实验环境里很实用。参数说明8020是 NameNode 的 RPC 端口Hadoop 3.x 默认是8020有些发行版用9000以你集群的core-site.xml为准。HADOOP_USER_NAME的值要和 HDFS 目录所有者匹配否则会报Permission denied。3. HDFS 读写流程的 Java 实现从流到代码的映射3.1 用 FileSystem API 完成文件上传与下载理解了 Shell 命令后Java API 的上传下载就是把它翻译成代码。下面这段代码实现了本地文件上传到 HDFS再从 HDFS 下载回来是实验报告里最常要求的核心代码。import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import java.io.*; public class HdfsUploadDownload { public static void main(String[] args) throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfs://namenode-host:8020); System.setProperty(HADOOP_USER_NAME, root); FileSystem fs FileSystem.get(conf); // 本地文件路径与 HDFS 目标路径 Path localPath new Path(/home/user/data.txt); Path hdfsPath new Path(/user/experiment/input/data.txt); // 上传本地 - HDFS fs.copyFromLocalFile(localPath, hdfsPath); System.out.println(上传完成); // 下载HDFS - 本地 Path downloadPath new Path(/home/user/downloaded.txt); fs.copyToLocalFile(hdfsPath, downloadPath); System.out.println(下载完成); // 关闭文件系统 fs.close(); } }逻辑说明copyFromLocalFile内部封装了FSDataOutputStream的写入流程copyToLocalFile封装了FSDataInputStream的读取流程。这两个方法适合快速实现但如果你想理解底层就需要手动操作流。参数说明copyFromLocalFile有多个重载默认会删除本地源文件delSrctrue如果不想删传false。copyToLocalFile同理。fs.close()必须调用否则连接池不释放多次运行会耗尽资源。3.2 手动操作 FSDataInputStream 与 FSDataOutputStream实验里经常要求不用封装方法手动实现读写这时候就要直接操作流。下面这段代码展示了如何用FSDataOutputStream写入数据再用FSDataInputStream读出来。import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import java.io.*; public class HdfsStreamDemo { public static void main(String[] args) throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfs://namenode-host:8020); System.setProperty(HADOOP_USER_NAME, root); FileSystem fs FileSystem.get(conf); // 写入创建输出流写入字符串 Path writePath new Path(/user/experiment/output/stream_test.txt); FSDataOutputStream out fs.create(writePath, true); // true 表示覆盖 out.write(Hello HDFS Stream\n.getBytes(UTF-8)); out.write(Second line\n.getBytes(UTF-8)); out.close(); System.out.println(写入完成); // 读取打开输入流逐字节读取 FSDataInputStream in fs.open(writePath); BufferedReader reader new BufferedReader(new InputStreamReader(in, UTF-8)); String line; while ((line reader.readLine()) ! null) { System.out.println(读取: line); } reader.close(); in.close(); fs.close(); } }逻辑说明fs.create()返回FSDataOutputStream数据先写入客户端缓冲区再按块传到 DataNode。fs.open()返回FSDataInputStream读取时先从最近的 DataNode 拉取块数据。参数说明fs.create(path, overwrite)的第二个参数控制是否覆盖已存在文件默认true。out.write()写入的是字节数组中文要用getBytes(UTF-8)避免乱码。in.seek(offset)可以随机定位做断点续读时很有用。3.3 HDFS 读写流程的底层拆解HDFS 读写流程是实验报告里必问的部分。写流程的核心步骤Client 调用create()→ NameNode 检查权限和文件是否存在 → NameNode 返回可用的 DataNode 列表 → Client 建立 Pipeline 写入 → 数据块按 128MB 切分 → 每个块写完后 DataNode 向 NameNode 汇报。读流程Client 调用open()→ NameNode 返回块位置 → Client 从最近的 DataNode 读取 → 读取完成后关闭流。这里有个关键点HDFS 的块大小默认是 128MBHadoop 2.x 以后副本数默认是 3。写数据时Client 不是直接写 NameNode而是拿到 DataNode 列表后自己建立连接。NameNode 只负责元数据管理不参与数据传输这也是 HDFS 能支撑高吞吐的原因。注意如果写入过程中某个 DataNode 失败Pipeline 会重建Client 会继续写剩余的副本。这个过程对上层透明但会在 NameNode 的日志里留下记录。排查写入慢的问题时可以看 DataNode 的dfs.datanode.max.transfer.threads参数是否够用。4. HDFS 编程实践避坑指南5 个血泪教训4.1 坑一FileSystem.get() 连到本地文件系统现象代码运行没报错但文件出现在本地目录HDFS 上找不到。原因classpath 下没有core-site.xml或者fs.defaultFS配置的是file:///。解决在代码里显式conf.set(fs.defaultFS, hdfs://host:8020)或者把集群的core-site.xml放到src/main/resources。用fs.getUri()打印确认当前连接的地址。4.2 坑二Permission denied 权限拒绝现象mkdir或create时报org.apache.hadoop.security.AccessControlException: Permission denied。原因HDFS 上的目录所有者是hadoop用户而你的代码以当前系统用户运行。解决设置System.setProperty(HADOOP_USER_NAME, hadoop)或者用hdfs dfs -chmod 777 /user/experiment放开权限。实验环境推荐前者生产环境要走 Kerberos 认证。4.3 坑三中文乱码现象写入的中文字符串读出来变成问号或乱码。原因getBytes()没指定编码用了平台默认编码Windows 下是 GBK。解决统一用getBytes(UTF-8)和new InputStreamReader(in, UTF-8)。HDFS 本身不关心编码存的是字节流编码问题全在客户端。4.4 坑四流未关闭导致连接泄漏现象程序运行几次后报java.io.IOException: Too many open files或连接超时。原因FSDataInputStream、FSDataOutputStream、FileSystem没有关闭。解决用 try-with-resources 或在 finally 块里关闭。FileSystem是重量级对象建议整个应用复用一个实例不要每次操作都get()一个新对象。4.5 坑五小文件过多拖垮 NameNode现象上传大量小文件后NameNode 内存飙升hdfs dfs -ls变慢。原因每个文件、每个块在 NameNode 内存里占约 150 字节小文件多了元数据爆炸。解决实验里如果只是测试问题不大。生产环境要用Har归档或CombineFileInputFormat合并小文件。做 HDFS 和 MapReduce 综合实训时小文件会直接拖慢 Map 任务启动速度。5. 进阶技巧用 HDFS API 做文件元数据批量分析实验做完基础读写后可以进一步用 API 做元数据统计这也是 HDFS 和 MapReduce 综合实训里常见的预处理步骤。下面这段代码遍历 HDFS 目录统计文件数量、总大小和副本分布。import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; public class HdfsMetaAnalysis { public static void main(String[] args) throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfs://namenode-host:8020); System.setProperty(HADOOP_USER_NAME, root); FileSystem fs FileSystem.get(conf); Path dir new Path(/user/experiment); FileStatus[] statuses fs.listStatus(dir); long totalSize 0; int fileCount 0; for (FileStatus status : statuses) { if (status.isFile()) { fileCount; totalSize status.getLen(); System.out.printf(文件: %s, 大小: %d bytes, 副本: %d, 块大小: %d%n, status.getPath().getName(), status.getLen(), status.getReplication(), status.getBlockSize()); } } System.out.printf(总计: %d 个文件, %d bytes%n, fileCount, totalSize); fs.close(); } }逻辑说明fs.listStatus()返回目录下所有文件和子目录的FileStatus数组。FileStatus封装了路径、长度、副本数、块大小、所有者、修改时间等元数据是做数据治理的基础。参数说明getReplication()返回副本数getBlockSize()返回块大小默认 134217728 字节即 128MB。如果目录下有子目录listStatus不会递归需要自己写递归或改用fs.listFiles(path, true)。验证方法跑完这段代码后对比hdfs dfs -count /user/experiment的输出文件数和总大小应该一致。如果不一致检查是否有隐藏文件以.或_开头的文件会被某些命令过滤。我自己的习惯是每次做完 HDFS 实验都会用hdfs fsck /path -files -blocks -locations再确认一遍块分布确保没有丢块或副本不足。这个习惯帮我提前发现过好几次 DataNode 磁盘满导致的写入异常。希望帮到你。本文还有配套的精品资源点击获取