HDFS实验避坑指南:读写流程、常用命令与Java API
发布时间:2026/10/7 11:48:32 锦皓数字建站

简介一份面向大数据初学者与Hadoop课程实验者的HDFS操作实验报告聚焦HDFS在Hadoop体系中的核心角色覆盖常用Shell命令与Java API两大操作路径。报告内容完整含实验目的、实验平台说明、环境信息与详细实现过程针对文件上传、存在性判断、追加内容、覆盖写入等典型场景既给出了hdfs dfs -put、-test -e、-appendToFile、-copyFromLocal -f等命令示例也配套了基于Configuration、FileSystem、Path类的Java代码实现便于对照理解命令行与编程接口的对应关系。压缩包内含1个docx文档约3.4MB适合提交课程作业或作为实验复习参考资料。此实验报告已有10211人学习是大数据入门阶段不可跳过的基础训练能帮助读者快速建立HDFS操作直觉并为后续MapReduce与HBase学习打底。1. 从一次“connection refused”说起这份HDFS实验资源能帮你少踩多少坑上周实验课上我照着课件在终端敲下hdfs dfs -mkdir -p /input然后hdfs dfs -put data.txt /input结果卡了半分钟直接抛java.net.ConnectException: Connection refused。当时第一反应是NameNode没起来结果jps一看进程都在再查网络才发现是客户端解析的hostname不对9000端口根本没被正确访问到。这种问题在“实验二熟悉常用的HDFS操作”里太典型了。这份实验资源把常用命令、读写流程、Java API和排错方法揉在了一起不是给你一份命令速查表而是让你在敲命令之前先想清楚这条命令背后是哪几个角色在协作、哪个端口在监听、哪个参数会影响最终结果。适合两类人一类是正在做大数据的实验课、急着交报告的学生另一类是刚接手HDFS集群、需要快速定位问题的运维或开发。它能帮你把“填鸭式敲命令”变成“按图索骥式做实验”真正减少翻车次数。2. 先把读写流程参透NameNode、DataNode与一组必须背下来的端口不少同学一上来就死记hdfs dfs -put可报错时还是两眼一抹黑。其实HDFS的命令大部分是客户端和集群内部角色协作的外在表现你不理解角色和端口命令敲得再熟也白搭。这一章先把底层逻辑打通再回来看命令你会发现很多参数都是顺理成章。2.1 NameNode和DataNode角色分工与一组必须背下来的端口HDFS是典型的主从架构。NameNode负责管理元数据目录树、文件块到DataNode的映射关系、权限和副本信息。DataNode负责实际存储把文件拆成block后落盘并且周期性向NameNode上报心跳和block报告。客户端读写数据时不会绕开NameNode所有元数据操作都得经过它。实验里最常踩的坑就是端口和角色对不上。不同Hadoop版本默认端口变化比较大我习惯把它们整理成一张表贴在终端旁边角色进程RPC端口默认HTTP端口默认说明NameNode元数据服务8020 或 9000500702.x / 98703.xRPC是客户端命令和Java API连的端口DataNode数据存储98663.x / 500102.x98643.x / 500752.xHTTP用于文件预览和Web UISecondaryNameNode辅助检查点500903.x50090不是NameNode的热备为什么“必须背下来”因为实验环境里最常见的错误是core-site.xml中fs.defaultFS写的是hdfs://localhost:9000但NameNode实际监听的是hdfs://namenode:8020两边对不上于是出现最经典的Connection refused。另一个常见错误是端口被防火墙挡了你看到进程存在但外部连不上。动手验证时我一般按这三步走# 第一步确认NameNode进程存活 jps # 第二步确认RPC端口到底在监听哪个IP地址 ss -tlnp | grep -E 8020|9000 # 第三步从客户端拿NameNode实际配置 hdfs getconf -namenodes这里jps能看到NameNode、DataNode、SecondaryNameNode这些Java进程名ss -tlnp能看到端口监听在0.0.0.0还是某个内网IP。如果端口只监听了127.0.0.1客户端又在另一台机器上那自然连不上。hdfs getconf -namenodes会打印客户端视角下NameNode的地址明确和core-site.xml里的配置是否一致。这三步做完80%的连接问题都能定位到具体原因。2.2 HDFS写文件流程管道写入和副本确认的每一步读懂了角色和端口再看HDFS写文件的流程你的“hdfs读写流程”才算真正建立起来。整体分六个步骤客户端调用create或mkdirs请求NameNode在命名空间里创建文件条目。NameNode检查路径是否存在、父目录是否存在、当前用户是否有写权限。通过后返回一个可以写入的DataNode列表。客户端将文件分块默认block大小128MB把第一个block推送到列表中的第一个DataNode。第一个DataNode收到后将数据以pipeline方式传给第二个DataNode第二个再传给第三个。每个DataNode写入成功后都会向上游返回ACK确认。客户端收到该block所有副本的ACK后继续写下一个block直到所有数据写完。客户端调用closeNameNode收到完成信号正式提交文件元数据此时文件可见。这个流程直接解释了几个实验现象。比如为什么dfs.replication设为2时上传大文件会比设为1慢因为客户端要等第二个副本确认网络往返更多。再比如为什么副本数不足时fsck会报告Under-replicated blocks因为写入是流水线式的如果某个DataNode在写过程中挂了副本数就会低于预期。想验证自己是不是真理解了建议跑一条命令hdfs fsck /user/hadoop/data.txt -files -blocks -locations这条命令会列出文件由哪几个block组成每个block的副本分布在哪个DataNode上。比如你设置了dfs.replication2这里会看到每个block对应两个副本位置如果只有一个副本说明集群配置或写入参数没有生效。这个验证方法在整个实验二里都非常有用尤其是后续做MapReduce综合实训时输入文件损坏会导致作业失败提前用fsck扫一遍能省大量排错时间。3. hdfs常用命令落地从ls到fsck的参数边界与实战场景“hdfs常用命令”这个热词几乎覆盖了实验二的所有操作题。但网上很多速查表只写命令不写参数边界导致你按它敲完在实验报告里却说不清楚每条命令的作用。这一章我把命令分成文件操作和管理操作两类参数含义和典型场景一起说。3.1 文件操作命令ls、mkdir、put、get、cp、mv、rm文件操作命令是实验二的主体下面这段把最常用的几条集合在一起可以直接在终端里跑# 创建多级目录-p 参数和Linux一致 hdfs dfs -mkdir -p /user/hadoop/input # 上传本地文件到HDFS-f 表示覆盖HDFS上已有的同名文件 hdfs dfs -put -f data.txt /user/hadoop/input/ # 从HDFS下载到当前目录-p 保留文件属性时间戳、权限 hdfs dfs -get -p /user/hadoop/input/data.txt ./ # 复制文件-f 覆盖目标-p 保留属性 hdfs dfs -cp -f /user/hadoop/input/data.txt /user/hadoop/input/data_copy.txt # 移动/重命名 hdfs dfs -mv /user/hadoop/input/data_copy.txt /user/hadoop/input/data_renamed.txt # 删除文件-skipTrash 表示跳过回收站马上释放空间 hdfs dfs -rm -skipTrash /user/hadoop/input/data_renamed.txt # 查看目录树-R 递归显示子目录 hdfs dfs -ls -R /user/hadoop每个参数都要说到位。mkdir -p如果父目录不存在会自动创建没有-p时父目录不存在会报错。put实际上是copyFromLocalFile的别名第二个参数指向HDFS路径如果不写完整路径比如直接hdfs dfs -put data.txt /input那么/input会被解析成根目录下的input而不是/user/当前用户/input这里很容易踩坑。get是copyToLocalFile本地文件已存在时不会覆盖必须加-f。rm默认进回收站如果你把文件删了然后发现空间没有立即释放就是因为回收站机制后面避坑章节我会再展开讲。还有三个命令虽然不在“必考”范围内但在实验排错时非常有用# 查看文件内容适合小文件 hdfs dfs -cat /user/hadoop/input/data.txt # 查看文件最后1KB适合大文件尾块 hdfs dfs -tail /user/hadoop/input/data.txt # 自动识别SequenceFile/压缩文件适合预览MapReduce输出 hdfs dfs -text /user/hadoop/output/part-r-00000cat遇到二进制文件会乱码tail只能看文件末尾text则能自动识别SequenceFile和压缩格式。综合实训里MapReduce输出经常是SequenceFile你用cat看就是一堆二进制乱码换text就能直接读出key-value内容这个技巧在实验报告和排错中都很加分。3.2 系统状态命令fsck、dfsadmin、report、du、df实验二不光是文件操作还经常要求你查看集群状态。这一组命令帮助你从“数据视角”切到“管理视角”。# 检查文件的块分布和健康状况 hdfs fsck /user/hadoop/input -files -blocks -locations # 查看整个集群的DataNode状态、容量、磁盘使用情况 hdfs dfsadmin -report # 查看目录/文件占用空间-h 表示以人类可读单位MB/GB显示 hdfs dfs -du -h /user/hadoop # 查看整个文件系统的容量和剩余空间 hdfs dfs -df -h / # 获取当前安全模式状态 hdfs dfsadmin -safemode getfsck是文件系统检查工具参数-files显示文件列表-blocks显示block ID-locations显示每个block所在的DataNode地址。三个参数合起来基本就是一张HDFS物理分布图。dfsadmin -report是集群健康状态的入口输出会包含每个DataNode的主机名、容量、已用空间、剩余空间和最后的通信时间。实验报告里要求“验证集群状态”时截这张图就能得分。du -h不带-h时输出的是字节数写进实验报告经常要转换单位记不清就容易出错。df -h和Linux的df类似只是显示的是HDFS整体容量。安全模式是NameNode启动期间的只读模式如果safemode get返回ON说明集群还在启动或block缺失严重此时put大文件会报“Name node is in safe mode”不是你的命令写错了而是集群没准备好。4. HDFS编程实践用Java API把命令行操作变成代码实验二通常不只要求敲命令还要求写Java代码完成上传下载这就是“hdfs编程实践”部分。很多课程把这部分设计为后续MapReduce实验的铺垫因为MapReduce作业要读写HDFS早晚要接触FileSystem。把命令行的功能用代码实现一遍你对FileSystem抽象才有手感。4.1 环境准备Maven依赖、core-site.xml与log4j配置先解决依赖问题。如果你用Mavenpom.xml里加以下依赖即可dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-client/artifactId version3.3.6/version /dependency我这里用的是Hadoop 3.x的客户端。如果你的实验环境是Hadoop 2.x把版本号换成2.10.2或和你集群版本一致。需要注意hadoop-client依赖会把HDFS、MapReduce和Common模块全部拉进来无需再单独引入hadoop-hdfs或hadoop-common。依赖配好后还需要把集群上的core-site.xml放到项目src/main/resources目录下否则客户端不知道NameNode地址。FileSystem.get()会默认从classpath读取这个配置文件。如果你手边没有集群的配置文件也可以直接在代码里硬编码conf.set(fs.defaultFS, hdfs://namenode:9000);但这样做不推荐因为代码和集群地址耦合太紧换环境就要改代码。我一般会在resources里放一份真实的core-site.xml保持代码干净。另外建议配一下log4j不然跑程序时控制台会刷大量Hadoop日志严重干扰输出。最简单的方式是在src/main/resources下放一个log4j.propertieslog4j.rootLoggerWARN, console log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.layoutorg.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p %c %x - %m%nWARN级别会过滤掉INFO级别的日志只输出警告和错误这样你跑代码时能看到自己的System.out输出而不会被一堆INFO util.VersionInfo刷屏。4.2 核心代码实现上传、下载、删除与目录创建下面是一个完整的可运行类演示了目录创建、本地上传HDFS、HDFS下载本地、删除文件四个操作。代码里的注释必须认真看参数含义都在注释里。package com.example.hdfs; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import java.io.IOException; public class HdfsApp { static Configuration conf new Configuration(); static { // 从classpath加载core-site.xml conf.addResource(core-site.xml); } public static void main(String[] args) throws IOException { FileSystem fs FileSystem.get(conf); // 1. 创建目录第二个参数true表示递归创建父目录 Path dir new Path(/user/hadoop/java-api); if (!fs.exists(dir)) { fs.mkdirs(dir); } // 2. 本地上传HDFS Path localFile new Path(data.txt); Path hdfsFile new Path(dir, data.txt); // copyFromLocalFile(delSrc, overwrite, src, dst) // delSrctrue 表示上传完成后删除本地文件这里用false // overwritetrue 表示HDFS上已有同名文件时覆盖 fs.copyFromLocalFile(false, true, localFile, hdfsFile); // 3. HDFS下载本地 Path localOut new Path(data_download.txt); // copyToLocalFile(delSrc, src, dst, useRawLocalFileSystem) // delSrctrue 表示下载后删除HDFS源文件这里用false // useRawLocalFileSystemtrue 表示使用本地原始文件系统损坏文件校验 fs.copyToLocalFile(false, hdfsFile, localOut, true); // 4. 删除HDFS文件第二个参数true表示递归删除目录 fs.delete(new Path(dir, data.txt), false); fs.close(); } }这段代码逻辑不复杂但有两个参数容易记反。copyFromLocalFile的第一个参数是“是否删除本地源文件”第二个参数是“是否覆盖HDFS目标文件”copyToLocalFile的第一个参数是“是否删除HDFS源文件”第四个参数是“是否使用本地原始文件系统”。如果不小心把copyFromLocalFile的第一个参数写成true你的本地文件就会被删掉这个教训我在实验室见过不止一次。打包并提交到Hadoop集群上运行的方式如下mvn clean package -DskipTests hadoop jar target/hdfs-demo-1.0.jar com.example.hdfs.HdfsApphadoop jar是Hadoop提供的jar运行入口它会设置好classpath和Hadoop相关环境变量。如果你的类依赖了集群配置文件确保jar包里的resources目录包含了core-site.xml或hdfs-site.xml。在本地IDEA里跑也能通过只要配置文件指向的NameNode地址可达即可。这一章做完你就同时掌握了命令和API两条路径。后续写MapReduce代码时FileSystem这个类你会在Driver里反复用到提前熟悉非常值得。5. HDFS操作避坑指南五个真实踩过的问题与排查方法这一章是血泪经验汇总。以下五个问题几乎每个做实验二的人都会遇到至少两个。每条我都按“现象 → 原因 → 解决”的顺序写方便你排错时直接查。5.1 连接和路径Client连不上NameNode、put写到了本地问题一所有命令都报Connection refused。现象执行hdfs dfs -ls /时终端卡顿后直接抛java.net.ConnectException: Connection refused但jps显示NameNode和DataNode进程都在。原因大部分情况是core-site.xml里fs.defaultFS配的hostname或端口和NameNode实际监听的不一致。比如配置写的是hdfs://localhost:9000但NameNode监听的是hdfs://namenode:8020或者防火墙没有放行对应端口。解决首先在NameNode节点上执行jps确认进程然后执行ss -tlnp | grep 8020或ss -tlnp | grep 9000确认监听地址。如果端口监听在127.0.0.1说明配置里绑定了回环地址客户端从其他机器连不上如果监听在0.0.0.0或真实内网IP说明端口本身没问题再检查客户端的hosts文件能否正确解析NameNode主机名。最后用hdfs getconf -namenodes查看客户端视角的地址和NodeManager上报的地址对比找出差异。问题二hdfs dfs -put data.txt /input执行成功但文件到了本地文件系统。现象上传后HDFS上找不到文件反而在当前目录下多了一个/input/data.txt或者干脆立即报错No such file or directory。原因客户端没有正确加载HDFS配置FileSystem默认使用本地文件系统。常见原因是环境变量HADOOP_CONF_DIR或者HADOOP_HOME没有指向集群配置文件目录导致命令没有识别fs.defaultFS。另一种可能是你在某个目录下建了一个叫/input的本地目录客户端把put目标解析成了本地路径。解决执行hdfs dfs -ls /如果显示的是本地目录而不是HDFS根目录说明配置没有加载。检查core-site.xml是否在classpath中对于命令行确认$HADOOP_HOME/etc/hadoop目录存在且被正确加入环境变量。更稳妥的做法是显式指定配置目录export HADOOP_CONF_DIR/usr/local/hadoop/etc/hadoop然后再跑命令。5.2 数据与权限副本数不对、Permission denied、删文件空间不释放问题三设置了dfs.replication1但fsck显示文件有多个副本。现象在hdfs-site.xml里已经把dfs.replication设成1重启集群后上传新文件用fsck检查却发现副本数仍是2或3。原因副本数不是一个纯服务端全局配置。NameNode确实会读取dfs.replication作为默认副本数但客户端可以通过-D dfs.replication1或Java API里的conf.set(dfs.replication, 1)覆盖这个默认值。如果你的服务器配置没有下载到客户端而客户端使用了自己环境的默认副本数就会出现不一致。更隐蔽的是hdfs-site.xml里配置的副本数只对新创建的文件生效已存在的文件的副本数不会自动调整。解决上传时显式指定副本数比如hdfs dfs -D dfs.replication1 -put data.txt /user/hadoop/input/Java代码里用conf.set(dfs.replication, 1);在使用put之前设置。还可以在命令执行后立刻用hdfs fsck /user/hadoop/input/data.txt -files -blocks -locations验证。如果已验证生效说明确实是客户端参数覆盖了服务端配置。问题四上传或下载时报Permission denied。现象执行hdfs dfs -put data.txt /user/hadoop时提示Permission denied: userubuntu, accessWRITE, inode/user/hadoop:hadoop:supergroup:drwxr-xr-x。原因HDFS权限模式默认开启。Linux当前用户是ubuntu而HDFS上/user/hadoop目录的所有者是hadoop其他用户只有读权限没有写权限。虽然你可能在Linux上有root权限但HDFS的用户名是客户端进程的OS用户名不是root。解决最简单的方式是设置环境变量指定HDFS用户export HADOOP_USER_NAMEhadoop hdfs dfs -put data.txt /user/hadoop/或者在Java代码中设置System.setProperty(HADOOP_USER_NAME, hadoop)这行必须在FileSystem.get()之前执行。注意这只是在客户端“模拟”用户身份实际能否写成功还是由NameNode的权限校验决定。如果HDFS系统关闭了权限校验则不会报这个错。问题五删除大文件后磁盘空间没有释放。现象执行hdfs dfs -rm /user/hadoop/bigfile成功后再用hdfs dfs -df -h /查看发现剩余空间没有变化。原因HDFS有回收站机制rm并不会真正删除block而是把文件移动到/user/username/.Trash目录下。默认情况fs.trash.interval可能配置为0或大于0如果大于0block会在回收站保留一段时间所以空间没有立刻释放。解决如果你确定文件不需要保留删除时加上-skipTrash参数hdfs dfs -rm -skipTrash /user/hadoop/bigfile如果已经删过文件且空间被回收站占用可以清空回收站hdfs dfs -expunge注意expunge会清理所有用户的回收站生产环境执行时要谨慎不过实验环境无所谓。通过-skipTrash删除后用hdfs dfs -df -h /能立刻看到容量变化。6. 衔接MapReduce综合实训一个秒级检查HDFS状态的小技巧前面的操作和代码都完成之后你就可以往“实验5 hdfs和mapreduce综合实训”方向走了。MapReduce作业跑完后输出目录里常见的是part-r-00000这样的文件但格式可能是纯文本、SequenceFile甚至压缩文件。这时候最有效的利器就是hdfs dfs -text。它支持自动识别SequenceFile和压缩格式比cat稳定得多。我通常在综合实训里建立一套“三秒检查”习惯。第一秒看输出目录大小第二秒直接预览输出前几十行第三秒检查输入文件块是否健康。对应命令如下# 第一秒确认输出目录不是空的大小不为0 hdfs dfs -du -h /user/hadoop/output # 第二秒预览前50行内容 hdfs dfs -text /user/hadoop/output/part-r-00000 | head -50 # 第三秒检查输入文件是否有损坏块 hdfs fsck /user/hadoop/input -files -blocks -locationshdfs dfs -du -h的输出是一个目录下的总大小如果显示0B说明MapReduce作业可能没有reduce输出或者写到了别的路径。text配合head管道这里很有讲究大文件不带head直接text终端会刷几千行卡到你怀疑人生带上head -50只取前50行既能判断输出格式是否正确又不会淹没在数据里。fsck如果出现CORRUPT说明输入块损坏作业跑一半会失败提前发现能省至少一小时。这个小技巧其实是从一次失败的实训作业里总结出来的。当时我负责的MapReduce作业报Task failed但看起来代码没问题。我花了两个小时找原因最后才发现是前一天上传输入文件时集群在某次断电后有一部分block变成CORRUPTfsck一查就暴露了。从那以后我每次跑综合实训前都强制走一遍“输出目录大小、输出内容预览、输入块健康检查”这三步再也没被这类基础问题绊倒过。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。