
简介本资源为大数据课程实验二的HDFS编程实践实验报告面向正在学习Hadoop与分布式文件系统的高校学生及大数据入门开发者帮助读者理解HDFS在Hadoop体系结构中的角色并掌握Shell命令与Java API两类基本文件操作。资源包内含1个docx文档约323KB内容涵盖实验内容、实验目的、过程截图及说明、实验总结与心得体会完整记录了使用hdfs dfs -put、-get、-ls、-rm等命令进行文件上传下载与目录管理以及通过FileSystem类实现文件创建、写入、读取和删除的Java API实践过程。文档结构清晰配有操作截图与代码说明可作为实验报告模板参考也可用于对照复盘HDFS常用命令与API调用方式适合需要完成同类实验或巩固HDFS基础操作的读者。目前已有2910人学习下载。1. 大数据实验二-HDFS编程实践从命令行到Java API一次把读写流程跑透很多人做「大数据实验二-HDFS编程实践」时卡住的不是概念而是第一次用 Java 代码去连一个真实的 HDFS 集群结果Connection refused、No FileSystem for scheme hdfs、权限拒绝轮番上阵。这个实验的核心诉求其实很明确把 HDFS 的读写流程从命令行操作升级到编程接口用代码完成文件上传、下载、目录遍历、块信息查看这些动作。它适合刚学完 HDFS 架构、需要动手验证「NameNode 管元数据、DataNode 存块」这条链路的学生和转行工程师。命令行会用不等于编程会用实验二真正要你跨过的坎是理解客户端在代码层面怎么跟 NameNode 和 DataNode 打交道。2. HDFS 编程实践的前置环境与最小可跑通配置2.1 集群侧要确认的三件事在写第一行 Java 代码之前先把集群状态确认清楚否则后面所有报错都会指向错误方向。常见做法是登录到 NameNode 所在节点依次执行下面三条命令。# 1. 确认 HDFS 进程是否正常应看到 NameNode、DataNode、SecondaryNameNode jps # 2. 确认 HDFS 处于非安全模式Safe mode is OFF 才能写入 hdfs dfsadmin -safemode get # 3. 确认根目录可访问能列出目录说明 RPC 端口通 hdfs dfs -ls /jps看的是进程存活safemode get看的是写入开关hdfs dfs -ls /验证的是客户端到 NameNode 的 RPC 链路。三条都通过才说明集群侧没有阻塞编程调用。如果jps里没有 DataNode先别急着写代码DataNode 掉线会导致块写入失败表现为代码里create卡住然后超时。2.2 客户端依赖与 core-site.xml 的坑Java 项目连 HDFS最容易被忽略的是配置文件。客户端需要知道 NameNode 的地址这个信息来自core-site.xml里的fs.defaultFS。有两种做法把集群的配置文件拷到项目resources目录或者在代码里手动conf.set。我一般推荐前者因为和集群保持一致少改代码。!-- core-site.xml 关键项端口以你集群实际为准 -- configuration property namefs.defaultFS/name valuehdfs://namenode-host:8020/value /property /configurationMaven 依赖方面hadoop-client会把hadoop-common、hadoop-hdfs等一起拉进来版本必须和集群版本对齐否则会出现协议不兼容。参数上fs.defaultFS的端口常见是 8020 或 9000以你集群core-site.xml为准不要凭记忆写。提示Windows 上跑客户端常遇到winutils.exe缺失导致的权限报错实验环境建议直接在 Linux 客户端节点上编译运行省掉这类环境问题。3. 用 Java API 跑通 HDFS 读写上传、下载、遍历的最小代码3.1 初始化 FileSystem 与上传文件HDFS 编程实践的入口是拿到FileSystem对象它是所有操作的句柄。下面这段代码完成「本地文件上传到 HDFS」这个最基础动作。import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; public class HdfsUpload { public static void main(String[] args) throws Exception { // 加载 resources 下的 core-site.xml自动读取 fs.defaultFS Configuration conf new Configuration(); // 拿到 HDFS 文件系统句柄 FileSystem fs FileSystem.get(conf); Path local new Path(/home/data/hello.txt); // 本地源文件 Path remote new Path(/user/test/hello.txt); // HDFS 目标路径 // 第三个参数 true 表示目标已存在时覆盖 fs.copyFromLocalFile(false, true, local, remote); System.out.println(upload done: remote); fs.close(); // 释放连接避免资源泄漏 } }FileSystem.get(conf)会根据fs.defaultFS决定连哪个集群。copyFromLocalFile的四个参数依次是是否删除本地源、是否覆盖目标、本地路径、HDFS 路径。很多人把第二个参数写成false结果重复运行时抛FileAlreadyExistsException这就是覆盖开关没打开。fs.close()别省长任务里不关会积累连接。3.2 下载与目录遍历读方向的操作同样围绕FileSystem展开。下载用copyToLocalFile遍历用listStatus。import org.apache.hadoop.fs.FileStatus; // 下载HDFS - 本地 fs.copyToLocalFile(new Path(/user/test/hello.txt), new Path(/home/data/back.txt)); // 遍历目录打印每个文件的路径、长度、副本数 FileStatus[] statuses fs.listStatus(new Path(/user/test)); for (FileStatus st : statuses) { System.out.printf(path%s size%d replication%d%n, st.getPath(), st.getLen(), st.getReplication()); }listStatus返回的是FileStatus数组里面封装了路径、长度、块大小、副本数、修改时间等元数据。这些信息正是 NameNode 维护的元数据在客户端的投影遍历目录本质上是在读 NameNode 的元数据。getReplication()能直接看到副本因子验证集群dfs.replication配置是否生效时很好用。3.3 查看块信息验证读写流程要真正理解 HDFS 读写流程得看到「文件被切成块、块分布在不同 DataNode」这件事。getFileBlockLocations能拿到块的位置。import org.apache.hadoop.fs.BlockLocation; FileStatus st fs.getFileStatus(new Path(/user/test/hello.txt)); BlockLocation[] blocks fs.getFileBlockLocations(st, 0, st.getLen()); for (BlockLocation b : blocks) { System.out.println(block hosts: String.join(,, b.getHosts())); }getFileBlockLocations的第二个、第三个参数是起始偏移和长度传0和文件全长表示查整个文件。返回的BlockLocation里getHosts()是持有该块副本的 DataNode 主机名。写流程里客户端先向 NameNode 申请块位置再直接写 DataNode读流程里客户端从 NameNode 拿到块位置后直接读 DataNode。这段代码打印出的 hosts就是 NameNode 告诉客户端的「去哪读」。4. HDFS 编程实践避坑五条血泪排查记录4.1 报 No FileSystem for scheme hdfs现象运行时报java.io.IOException: No FileSystem for scheme hdfs。原因hadoop-hdfs依赖没进 classpath只有hadoop-common时识别不了 hdfs 协议。解决确认 Maven 里引入的是hadoop-client或同时引入hadoop-common和hadoop-hdfs用mvn dependency:tree检查。4.2 连接被拒绝 Connection refused现象FileSystem.get阶段抛Connection refused。原因fs.defaultFS指向的地址或端口不对或者 NameNode 的 RPC 端口没监听。解决核对core-site.xml里的端口在 NameNode 节点用netstat -tlnp | grep 8020确认监听状态客户端节点telnet namenode-host 8020验证连通性。4.3 权限拒绝 Permission denied现象写入时抛Permission denied: userxxx, accessWRITE。原因当前操作系统用户对目标 HDFS 目录没有写权限。解决用hdfs dfs -ls看目录属主切换到有权限的用户或让管理员hdfs dfs -chmod放开目录权限。实验环境里常见的是用 root 跑代码但 HDFS 目录属主是 hdfs。4.4 上传成功但文件长度为 0现象copyFromLocalFile没报错但listStatus看到文件 size 为 0。原因本地源文件路径写错或者源文件本身为空也可能是copyFromLocalFile第一个参数设成true把本地文件删了但没传成功。解决先确认本地文件存在且有内容第一个参数一般设false避免误删源文件。4.5 副本数不是预期的 3现象getReplication()返回 1 而不是 3。原因客户端conf里没加载集群的hdfs-site.xml用了默认副本因子或者上传时 DataNode 数量不足。解决把hdfs-site.xml一并放进resources确认dfs.replication的值并检查存活 DataNode 数量是否够。5. 进阶技巧用 IOUtils 做流式读写与副本因子动态调整命令行和copyFromLocalFile适合整文件搬运但真实场景经常需要流式处理比如边读边解析、只读文件的一段。这时用FSDataInputStream和FSDataOutputStream更灵活。import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.io.IOUtils; // 流式读取打开 HDFS 文件读到本地标准输出 FSDataInputStream in fs.open(new Path(/user/test/hello.txt)); try { IOUtils.copyBytes(in, System.out, 4096, false); // 4KB 缓冲不自动关闭流 } finally { IOUtils.closeStream(in); // 手动关闭避免泄漏 }IOUtils.copyBytes的第三个参数是缓冲区大小默认 4KB 够用大文件可以调到 64KB 减少系统调用。第四个参数close设false表示复制完不关流由finally里的closeStream统一关这样异常路径下也不会漏关。写方向同理用fs.create(path)拿到FSDataOutputStream配合IOUtils.copyBytes把本地流写进去。副本因子也可以在代码里动态改不用改集群配置// 把已有文件的副本因子改成 2 fs.setReplication(new Path(/user/test/hello.txt), (short) 2);setReplication第二个参数是short类型传2要强转否则编译不过。这个操作会触发 NameNode 调度 DataNode 复制或删除块适合验证副本机制。我一般会先用getFileBlockLocations看改之前的 hosts 数量改完再查一次对比副本分布的变化比单纯看配置直观得多。验证读写流程是否真的走通我的习惯是「三看」看listStatus的长度对不对、看getFileBlockLocations的 hosts 数量、看getReplication的值。三个都对上说明客户端到 NameNode、DataNode 的链路是通的实验二的目标就达到了。这套排查习惯帮我省了很多来回折腾的时间希望帮到你。本文还有配套的精品资源点击获取