HDFS的命令行与 Python API 交互
HDFS 实验操作指南:命令行与 Python API 交互
实验目标
-
掌握HDFS常用的Shell命令,能够通过命令行完成文件系统的基本操作(如创建目录、上传/下载文件、查看文件、删除等)。
-
理解HDFS的目录结构和文件存储的基本原理。
-
学习如何使用Python语言连接到HDFS,并以编程方式进行文件操作。
-
掌握在Windows PyCharm中配置WSL作为远程解释器,以连接到Docker中Hadoop环境的实践技巧。
实验环境准备
-
Windows 11/10: 已安装并启用WSL2。
-
WSL2: 已安装任一Linux发行版(如Ubuntu)。
-
Docker Desktop: 已在Windows上安装,并已配置为使用WSL2后端。
-
Hadoop Docker环境: 您的GitHub开源Hadoop项目已通过
docker-compose up -d或类似命令成功启动。请确保Hadoop集群处于健康运行状态。 -
PyCharm: Professional版(社区版不支持远程解释器)。
-
网络端口: 确保Hadoop NameNode的WebHDFS端口(默认为
9870)已经从Docker容器映射到了您的主机。通常在docker-compose.yml文件中会有类似ports: - "9870:9870"的配置。
第一部分:HDFS 命令行接口 (CLI) 操作
这部分操作需要进入到Hadoop NameNode的Docker容器内部来执行。HDFS的命令行工具可以让我们像操作本地Linux文件系统一样操作分布式文件系统。
步骤1:进入Hadoop NameNode容器
首先,我们需要获取一个通往Hadoop集群的“入口”,也就是NameNode容器的bash shell。
-
打开Windows的PowerShell或CMD终端。
-
列出当前正在运行的Docker容器,找到NameNode容器的名称或ID。
Bash
docker ps
您会看到类似下面的输出,请记下NameNode容器的名称(例如
hadoop-namenode-1)。CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a1b2c3d4e5f6 bde2020/hadoop-namenode:2.0.0-hadoop3.2.1-java8 "/entrypoint.sh /run…" 2 hours ago Up 2 hours 0.0.0.0:9000->9000/tcp, 0.0.0.0:9870->9870/tcp namenode ...
-
使用
docker exec命令进入该容器的交互式bash环境。Bash
docker exec -it namenode /bin/bash
-
docker exec: 在一个正在运行的容器中执行命令。 -
-it:-i(interactive) 保持标准输入打开,-t(tty) 分配一个伪终端。合起来就是我们熟悉的交互式Shell。 -
hadoop-namenode-1: 您的NameNode容器名。 -
/bin/bash: 要在容器内执行的命令,即启动bash shell。
-
成功后,您的命令提示符会变为类似 root@a1b2c3d4e5f6:/# 的形式,表示您已在容器内部。
步骤2:HDFS常用命令实践
所有HDFS的命令都以hdfs dfs开头,后面跟上具体的指令,与Linux命令非常相似。
-
检查HDFS状态
这是一个很好的起点,可以确认HDFS集群是否健康。
Bash
hdfs dfsadmin -report
-
命令含义:
-
hdfs dfsadmin: Hadoop分布式文件系统的管理命令。 -
-report: 生成一个关于集群当前状态的报告,会显示总容量、已用空间、可用空间以及存活/死亡的DataNode数量等信息。
-
-
-
创建目录 (mkdir)
我们将在HDFS的根目录下创建一个用于本次实验的专属目录。
Bash
hdfs dfs -mkdir -p /user/lab_exp
-
命令含义:
-
-mkdir: "make directory"的缩写,用于创建目录。 -
-p: "parent"的缩写,如果父目录(这里是/user)不存在,会自动创建它。这能避免因父目录不存在而导致的错误。 -
/user/lab_exp: 我们要在HDFS中创建的目录的绝对路径。
-
-
-
列出文件和目录 (ls)
查看我们刚刚创建的目录是否存在。
Bash
hdfs dfs -ls /user
命令含义:-
-ls: "list"的缩写,用于列出指定路径下的文件和目录信息,类似于ls -l。 -
预期输出: 您应该能看到刚刚创建的
lab_exp目录。
-
-
上传文件到HDFS (put/copyFromLocal)
我们将先在容器的本地文件系统创建一个示例文本文件,然后上传到HDFS。
Bash
# 在容器的/tmp目录下创建一个本地文件 echo "Hello HDFS from Docker container!" > /tmp/hello.txt # 将本地文件上传到HDFS的指定目录 hdfs dfs -put /tmp/hello.txt /user/lab_exp/
命令含义:-
/user/lab_exp/: 目标路径(在HDFS上)。 -
/tmp/hello.txt: 源文件路径(在容器的本地文件系统里)。 -
-put: 将文件或目录从本地文件系统复制到HDFS。 -
echo ... > ...: Linux命令,创建一个包含指定文本的文件。
-
-
查看HDFS中的文件内容 (cat)
不下载文件,直接在终端查看HDFS上文件的内容。
Bash
hdfs dfs -cat /user/lab_exp/hello.txt
命令含义:-
-cat: "concatenate"的缩写,将指定路径的文件内容输出到标准输出(也就是您的终端)。 -
预期输出:
Hello HDFS from Docker container!
-
-
从HDFS下载文件 (get/copyToLocal)
将HDFS上的文件下载回容器的本地文件系统。
Bash
# -f 选项表示如果本地已存在同名文件,则覆盖它 hdfs dfs -get -f /user/lab_exp/hello.txt /tmp/hello_from_hdfs.txt # 验证一下文件是否已下载到容器本地h ls -l /tmp cat /tmp/hello_from_hdfs.txt
命令含义:-
-f: "force"的缩写,强制覆盖本地同名文件。 -
-get: 将文件或目录从HDFS复制到本地文件系统。
-
-
删除HDFS上的文件和目录 (rm)
实验结束,清理我们创建的文件和目录。
Bash
# 删除文件 hdfs dfs -rm /user/lab_exp/hello.txt # 删除空目录 hdfs dfs -rmdir /user/lab_exp
命令含义:-
-rmdir: "remove directory"的缩写,只能用于删除空目录。 -
-rm: "remove"的缩写,用于删除HDFS上的文件。如果要删除非空目录,需要使用-rm -r。
-
-
退出容器
完成命令行操作后,输入以下命令返回到您的Windows终端。
Bash
exit
第二部分:使用 Python 操作 HDFS
这部分是本次实验的核心,我们将配置PyCharm,并编写Python脚本来完成与第一部分类似的文件操作。
步骤1:安装Python HDFS库
我们需要一个库来帮助Python与HDFS的WebHDFS API进行通信。hdfs是一个非常简单易用的选择。
-
在PyCharm底部的Terminal中,使用pip安装
hdfs库。Bash
pip install hdfs
步骤2:修改docker-compose.yml
这是最正确、最稳定的解决方案。我们需要通过环境变量来“覆盖”Hadoop的配置,告诉DataNode在向NameNode注册时,上报一个外部可以访问的地址。
-
找到
docker-compose.yml文件。 -
定位到
datanode服务,为它添加或修改environment部分,明确告诉它在向NameNode注册时,使用localhost作为自己的主机名。YAML
services: namenode: environment: - CLUSTER_NAME=test - HDFS_CONF_dfs_client_use_datanode_hostname=true ... # 其他配置保持不变 datanode: ... # 其他配置保持不变 ports: - "9864:9864" volumes: - hadoop_datanode:/hadoop/dfs/data environment: - SERVICE_PRECONDITION=namenode:9870 - HDFS_CONF_dfs_datanode_hostname=localhost - HDFS_CONF_dfs_client_use_datanode_hostname=true ...
更新: 一个更现代和可能更兼容的配置是,直接声明一个所有节点都能访问的域名。对于您的情况,最简单的是让datanode直接使用IP地址进行通信,而不是主机名。上面的CORE_CONF_环境变量是一种常见的方式,它会修改core-site.xml的配置。您需要根据您使用的Docker镜像的文档来确认修改配置的确切环境变量名称。但以上配置的意图是强制HDFS在节点间通信和客户端重定向时使用IP地址而非主机名。
-
重启Hadoop集群: 在
docker-compose.yml文件所在的目录下,打开终端,执行以下命令来让配置生效:Bash
docker-compose down docker-compose up -d
重启后,当NameNode再重定向您的Python客户端时,它就会提供一个基于IP的、您的Windows主机可以理解的地址,问题就解决了。
步骤3:编写Python代码操作HDFS
现在,在您的PyCharm项目中创建一个新的Python文件(例如 hdfs_experiment.py),并输入以下代码。
Python
# 导入hdfs库中的InsecureClient
from hdfs import InsecureClient
# --- 1. 连接到HDFS ---
# NameNode的WebHDFS端口默认是9870。由于Docker端口已映射,
# 并且我们的代码运行在WSL中,可以直接通过localhost访问。
# 'root' 是很多开源Hadoop Docker镜像的默认超级用户。
try:
client = InsecureClient('http://localhost:9870', user='root')
print("成功连接到HDFS!")
except Exception as e:
print(f"连接HDFS失败: {e}")
exit()
# 定义我们要在HDFS上操作的目录和文件路径
hdfs_base_dir = '/user/python_lab'
hdfs_file_path = f'{hdfs_base_dir}/greetings.txt'
local_download_path = './downloaded_from_hdfs.txt' # 下载到PyCharm项目目录下
try:
# --- 2. 创建目录 ---
# 使用 client.makedirs() 创建目录,它类似于 mkdir -p,即使目录已存在也不会报错。
client.makedirs(hdfs_base_dir)
print(f"HDFS目录 '{hdfs_base_dir}' 已创建或已存在。")
# --- 3. 列出目录内容,验证创建 ---
# client.list() 返回一个包含文件名和目录名的列表
dir_content = client.list('/user/')
print(f"/user/ 目录下的内容: {dir_content}")
if 'python_lab' in dir_content:
print("目录创建成功!")
# --- 4. 写入(上传)文件 ---
# 使用 with...as 语法可以安全地写入数据。
# data参数需要是字节串(bytes),所以字符串前要加'b'或进行encode()
file_content = "Hello HDFS from Python! This is a test."
with client.write(hdfs_file_path, encoding='utf-8', overwrite=True) as writer:
writer.write(file_content)
print(f"文件 '{hdfs_file_path}' 已成功写入。")
# --- 5. 读取(查看)文件内容 ---
# 使用 with...as 语法安全地读取数据。
with client.read(hdfs_file_path, encoding='utf-8') as reader:
content_from_hdfs = reader.read()
print(f"从HDFS读取到的文件内容:\n---\n{content_from_hdfs}\n---")
assert file_content == content_from_hdfs
# --- 6. 下载文件到本地 ---
# client.download() 返回下载到本地的文件路径
downloaded_path = client.download(hdfs_file_path, local_download_path, overwrite=True)
print(f"文件已从HDFS下载到本地: '{downloaded_path}'")
# 你可以检查一下PyCharm项目左侧的文件浏览器,会看到这个新文件
# --- 7. 清理实验文件和目录 ---
# client.delete() 可以删除文件或目录。
# recursive=True 表示如果删除的是目录,则递归删除其下所有内容。
deleted = client.delete(hdfs_base_dir, recursive=True)
if deleted:
print(f"实验目录 '{hdfs_base_dir}' 及内容已成功删除。")
except Exception as e:
print(f"操作HDFS时发生错误: {e}")
finally:
print("\n实验结束。")
步骤4:运行并理解Python代码
-
运行脚本: 在PyCharm中运行即可。
-
观察输出: 仔细观察PyCharm的运行控制台输出,它会一步步地显示连接、创建、写入、读取、下载和删除的过程。
-
代码讲解:
-
from hdfs import InsecureClient: 我们从hdfs库导入InsecureClient类。Insecure意味着我们没有配置Kerberos安全认证,这在实验环境中是常见的。 -
client = InsecureClient('http://localhost:9870', user='root'): 这是最关键的一步。我们创建一个客户端实例来与HDFS通信。 -
http://localhost:9870: 这是HDFS NameNode的WebHDFS服务的地址。因为我们的代码运行在WSL中,localhost可以正确地指向WSL自己,而Docker容器的9870端口已经映射到了WSL上。 -
user='root': 指定以哪个用户的身份来操作HDFS。HDFS有权限系统,root用户通常拥有最高权限。 -
client.makedirs(path): 创建目录,等同于hdfs dfs -mkdir -p。 -
client.list(path): 列出目录内容,等同于hdfs dfs -ls。 -
client.write(path, ...): 写入数据到HDFS文件,等同于echo "..." | hdfs dfs -put - path的编程版本。 -
client.read(path, ...): 从HDFS文件中读取数据,等同于hdfs dfs -cat。 -
client.download(hdfs_path, local_path): 从HDFS下载文件,等同于hdfs dfs -get。 -
client.delete(path, recursive=True): 删除文件或目录,等同于hdfs dfs -rm -r。
-
更多推荐

所有评论(0)