24.10.14
实验2
熟悉常用的HDFS操作
1.实验目的
(1)理解HDFS在Hadoop体系结构中的角色;
(2)熟练使用HDFS操作常用的Shell命令;
(3)熟悉HDFS操作常用的Java API。
2. 实验平台
(1)操作系统:Linux(建议Ubuntu16.04或Ubuntu18.04);
(2)Hadoop版本:3.1.3;
(3)JDK版本:1.8;
(4)Java IDE:Eclipse。
3. 实验步骤
(一)编程实现以下功能,并利用Hadoop提供的Shell命令完成相同任务:
(1) 向HDFS中上传任意文本文件,如果指定的文件在HDFS中已经存在,则由用户来指定是追加到原有文件末尾还是覆盖原有的文件;
Shell命令:
#!/bin/bash
local_file="/home/hadoop/wordfile1.txt"
hdfs_file="/input/wordfile1.txt"
hdfs dfs -test -e $hdfs_file
if [ $? -eq 0 ]; then
echo "文件已存在,选择操作:"
echo "1. 覆盖文件"
echo "2. 追加到文件末尾"
read -p "请输入选择 (1/2): " choice
if [ "$choice" == "1" ]; then
hdfs dfs -put -f $local_file $hdfs_file
echo "文件已覆盖。"
elif [ "$choice" == "2" ]; then
hdfs dfs -appendToFile $local_file $hdfs_file
echo "内容已追加。"
else
echo "无效选择。"
fi
else
hdfs dfs -put $local_file $hdfs_file
echo "文件已上传。"
fi
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
import java.io.*;
public class HDFSFileUpload {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String localFilePath = args[0]; // 本地文件路径
String hdfsFilePath = args[1]; // HDFS 文件路径
Path localPath = new Path(localFilePath);
Path hdfsPath = new Path(hdfsFilePath);
// 检查 HDFS 文件是否存在
if (fs.exists(hdfsPath)) {
System.out.println("文件已存在,请选择:1.覆盖 2.追加");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String choice = br.readLine();
if ("1".equals(choice)) {
// 覆盖文件
fs.copyFromLocalFile(localPath, hdfsPath);
} else if ("2".equals(choice)) {
// 追加到文件
FSDataOutputStream out = fs.append(hdfsPath);
BufferedReader fileReader = new BufferedReader(new FileReader(localFilePath));
String line;
while ((line = fileReader.readLine()) != null) {
out.writeBytes(line + "\n");
}
fileReader.close();
out.close();
}
} else {
// 文件不存在,直接上传
fs.copyFromLocalFile(localPath, hdfsPath);
}
fs.close();
}
}
(2) 从HDFS中下载指定文件,如果本地文件与要下载的文件名称相同,则自动对下载的文件重命名;
Shell命令:
#!/bin/bash
# 指定HDFS文件路径
read -p "请输入HDFS文件路径: " hdfs_file
# 指定本地目标目录
read -p "请输入本地保存目录: " local_dir
# 获取HDFS文件名
filename=$(basename $hdfs_file)
# 检查本地目录中是否已存在同名文件
if [ -e "$local_dir/$filename" ]; then
# 如果文件已存在,生成新文件名
timestamp=$(date +"%Y%m%d%H%M%S")
new_filename="${filename%.*}_$timestamp.${filename##*.}"
local_file="$local_dir/$new_filename"
echo "本地文件已存在,下载的文件将重命名为: $new_filename"
else
# 如果文件不存在,使用原文件名
local_file="$local_dir/$filename"
fi
# 从HDFS下载文件
hdfs dfs -get $hdfs_file $local_file
# 确认下载结果
if [ $? -eq 0 ]; then
echo "文件已成功下载到: $local_file"
else
echo "文件下载失败,请检查HDFS路径和本地目录。"
fi
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
import java.io.*;
public class HDFSFileDownload {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
String localFilePath = args[1]; // 本地文件路径
Path hdfsPath = new Path(hdfsFilePath);
Path localPath = new Path(localFilePath);
// 如果本地文件已存在,自动重命名
if (fs.exists(hdfsPath)) {
if (new File(localFilePath).exists()) {
String newLocalFilePath = localFilePath + "_" + System.currentTimeMillis();
localPath = new Path(newLocalFilePath);
}
fs.copyToLocalFile(hdfsPath, localPath);
}
fs.close();
}
}
(3) 将HDFS中指定文件的内容输出到终端中;
Shell命令:
# 输出文件内容到终端
hdfs dfs -cat /input/wordfile1.txt
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
import java.io.*;
public class HDFSFileOutput {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
Path hdfsPath = new Path(hdfsFilePath);
if (fs.exists(hdfsPath)) {
FSDataInputStream in = fs.open(hdfsPath);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
in.close();
}
fs.close();
}
}
(4) 显示HDFS中指定的文件的读写权限、大小、创建时间、路径等信息;
Shell命令:
# 显示文件详细信息
hdfs dfs -ls /input/wordfile1.txt
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
import java.io.*;
public class HDFSFileInfo {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
Path hdfsPath = new Path(hdfsFilePath);
if (fs.exists(hdfsPath)) {
FileStatus status = fs.getFileStatus(hdfsPath);
System.out.println("路径: " + status.getPath());
System.out.println("权限: " + status.getPermission());
System.out.println("大小: " + status.getLen() + " 字节");
System.out.println("创建时间: " + status.getModificationTime());
System.out.println("是否是目录: " + status.isDirectory());
}
fs.close();
}
}
(5) 给定HDFS中某一个目录,输出该目录下的所有文件的读写权限、大小、创建时间、路径等信息,如果该文件是目录,则递归输出该目录下所有文件相关信息;
Shell命令:
# 递归显示目录内容
hdfs dfs -ls -R /input/
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSListDirectory {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsDirPath = args[0]; // HDFS 目录路径
Path hdfsDir = new Path(hdfsDirPath);
if (fs.exists(hdfsDir)) {
FileStatus[] fileStatuses = fs.listStatus(hdfsDir);
for (FileStatus fileStatus : fileStatuses) {
if (fileStatus.isDirectory()) {
System.out.println("目录: " + fileStatus.getPath());
// 递归列出目录内容
HDFSListDirectory.main(new String[]{fileStatus.getPath().toString()});
} else {
System.out.println("文件: " + fileStatus.getPath());
System.out.println("权限: " + fileStatus.getPermission());
System.out.println("大小: " + fileStatus.getLen());
System.out.println("创建时间: " + fileStatus.getModificationTime());
}
}
}
fs.close();
}
}
(6) 提供一个HDFS内的文件的路径,对该文件进行创建和删除操作。如果文件所在目录不存在,则自动创建目录;
Shell命令:
#!/bin/bash
# 输入文件的HDFS路径
read -p "请输入文件的HDFS路径: " hdfs_path
# 获取文件所在目录
dir_path=$(dirname "$hdfs_path")
# 检查目录是否存在,不存在则创建目录
hdfs dfs -test -e $dir_path
if [ $? -ne 0 ]; then
echo "目录不存在,正在创建目录:$dir_path"
hdfs dfs -mkdir -p $dir_path
else
echo "目录已存在:$dir_path"
fi
# 创建文件:检查文件是否存在,若不存在则创建空文件
hdfs dfs -test -e $hdfs_path
if [ $? -ne 0 ]; then
echo "文件不存在,创建文件:$hdfs_path"
hdfs dfs -touchz $hdfs_path
else
echo "文件已存在:$hdfs_path"
fi
# 删除文件
read -p "是否删除文件 $hdfs_path? (y/n): " delete_choice
if [ "$delete_choice" == "y" ]; then
echo "删除文件:$hdfs_path"
hdfs dfs -rm $hdfs_path
else
echo "未删除文件。"
fi
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSCreateDeleteFile {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
Path hdfsPath = new Path(hdfsFilePath);
// 创建文件及目录
if (!fs.exists(hdfsPath)) {
fs.createNewFile(hdfsPath); // 创建文件
fs.mkdirs(hdfsPath.getParent()); // 自动创建目录
}
// 删除文件
if (fs.exists(hdfsPath)) {
fs.delete(hdfsPath, true); // 删除文件
}
fs.close();
}
}
(7) 提供一个HDFS的目录的路径,对该目录进行创建和删除操作。创建目录时,如果目录文件所在目录不存在,则自动创建相应目录;删除目录时,由用户指定当该目录不为空时是否还删除该目录;
Shell命令:
#!/bin/bash
# 提示用户输入HDFS目录路径
read -p "请输入HDFS目录路径: " hdfs_dir
# 创建目录,如果目录不存在,则创建父目录
hdfs dfs -test -e $hdfs_dir
if [ $? -ne 0 ]; then
echo "目录不存在,正在创建目录:$hdfs_dir"
hdfs dfs -mkdir -p $hdfs_dir
echo "目录已创建:$hdfs_dir"
else
echo "目录已存在:$hdfs_dir"
fi
# 删除目录
read -p "是否删除目录 $hdfs_dir? (y/n): " delete_choice
if [ "$delete_choice" == "y" ]; then
# 检查目录是否为空
hdfs dfs -ls $hdfs_dir | grep -q "Found"
if [ $? -eq 0 ]; then
echo "目录不为空。"
read -p "目录不为空,是否强制删除?(y/n): " force_delete
if [ "$force_delete" == "y" ]; then
hdfs dfs -rm -r $hdfs_dir
echo "非空目录已删除:$hdfs_dir"
else
echo "操作已取消。"
fi
else
# 目录为空,直接删除
hdfs dfs -rmdir $hdfs_dir
echo "空目录已删除:$hdfs_dir"
fi
else
echo "未删除目录。"
fi
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSCreateDeleteDir {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsDirPath = args[0]; // HDFS 目录路径
Path hdfsDir = new Path(hdfsDirPath);
// 创建目录
if (!fs.exists(hdfsDir)) {
fs.mkdirs(hdfsDir); // 创建目录
}
// 删除目录
if (fs.exists(hdfsDir)) {
fs.delete(hdfsDir, true); // 删除目录
}
fs.close();
}
}
(8) 向HDFS中指定的文件追加内容,由用户指定内容追加到原有文件的开头或结尾;
Shell命令:
#!/bin/bash
# 提示用户输入HDFS文件路径
read -p "请输入HDFS文件路径: " hdfs_file
# 检查文件是否存在
hdfs dfs -test -e $hdfs_file
if [ $? -ne 0 ]; then
echo "HDFS文件不存在:$hdfs_file"
exit 1
fi
# 提示用户输入要追加的内容
read -p "请输入要追加的内容: " append_content
# 提示用户选择追加位置
read -p "请选择追加位置 (1-文件开头, 2-文件末尾): " choice
# 临时文件
temp_local_file="/tmp/temp_hdfs_file.txt"
temp_new_content="/tmp/new_content.txt"
if [ "$choice" -eq 1 ]; then
# 追加到文件开头
echo "$append_content" > $temp_new_content
hdfs dfs -cat $hdfs_file >> $temp_new_content
hdfs dfs -rm $hdfs_file
hdfs dfs -put $temp_new_content $hdfs_file
echo "内容已成功追加到文件开头:$hdfs_file"
elif [ "$choice" -eq 2 ]; then
# 追加到文件末尾
echo "$append_content" > $temp_new_content
hdfs dfs -appendToFile $temp_new_content $hdfs_file
echo "内容已成功追加到文件末尾:$hdfs_file"
else
echo "无效的选择,请输入1或2。"
fi
# 清理临时文件
rm -f $temp_new_content
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSDeleteFile {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
Path hdfsPath = new Path(hdfsFilePath);
if (fs.exists(hdfsPath)) {
fs.delete(hdfsPath, true); // 删除文件
}
fs.close();
}
}
(9) 删除HDFS中指定的文件;
Shell命令:
# 删除文件
hdfs dfs -rm /input/wordfile1.txt
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSDeleteFile {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String hdfsFilePath = args[0]; // HDFS 文件路径
Path hdfsPath = new Path(hdfsFilePath);
if (fs.exists(hdfsPath)) {
fs.delete(hdfsPath, true); // 删除文件
}
fs.close();
}
}
(10) 在HDFS中,将文件从源路径移动到目的路径。
Shell命令:
# 移动文件
hdfs dfs -mv /input/wordfile1.txt /output/
Java代码:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
public class HDFSMoveFile {
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
String srcPath = args[0]; // 源文件路径
String destPath = args[1]; // 目标文件路径
Path src = new Path(srcPath);
Path dest = new Path(destPath);
if (fs.exists(src)) {
fs.rename(src, dest); // 移动文件
}
fs.close();
}
}
(二)编程实现一个类“MyFSDataInputStream”,该类继承“org.apache.hadoop.fs.FSDataInputStream”,要求如下:实现按行读取HDFS中指定文件的方法“readLine()”,如果读到文件末尾,则返回空,否则返回文件一行的文本。
代码如下:
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.Configuration;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class MyFSDataInputStream extends FSDataInputStream {
private BufferedReader reader;
// 构造函数,初始化父类 FSDataInputStream,并创建 BufferedReader
public MyFSDataInputStream(FSDataInputStream inputStream) {
super(inputStream.getWrappedStream());
this.reader = new BufferedReader(new InputStreamReader(inputStream));
}
// 实现按行读取的方法
public String readLine() {
try {
String line = reader.readLine();
// 如果到达文件末尾,返回空
if (line == null) {
return "";
}
return line;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
// 关闭流
@Override
public void close() throws IOException {
super.close();
if (reader != null) {
reader.close();
}
}
public static void main(String[] args) throws IOException {
// 创建 Hadoop 配置对象
Configuration conf = new Configuration();
// 获取文件系统对象
FileSystem fs = FileSystem.get(conf);
// 指定要读取的文件路径
Path path = new Path("/user/hadoop/testfile.txt");
// 打开文件输入流
FSDataInputStream fsDataInputStream = fs.open(path);
MyFSDataInputStream myInputStream = new MyFSDataInputStream(fsDataInputStream);
// 逐行读取文件
String line;
while ((line = myInputStream.readLine()) != null) {
System.out.println(line);
}
// 关闭输入流
myInputStream.close();
fs.close();
}
}
(三)查看Java帮助手册或其它资料,用“java.net.URL”和“org.apache.hadoop.fs.FsURLStreamHandlerFactory”编程完成输出HDFS中指定文件的文本到终端中。
代码如下:
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FsURLStreamHandlerFactory;
import java.net.*;
import java.io.*;
public class HDFSFileReaderUsingURL {
public static void main(String[] args) {
try {
// 注册 Hadoop 的 URL 处理程序
URL.setURLStreamHandlerFactory(new FsURLStreamHandlerFactory());
// 设置 HDFS 配置
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://localhost:9000"); // 设置 HDFS 地址,替换成你的 HDFS 地址
// 指定要读取的 HDFS 文件路径
String hdfsPath = "hdfs://localhost:9000/user/hadoop/testfile.txt"; // HDFS 路径
// 创建 URL 对象
URL url = new URL(hdfsPath);
// 打开连接并读取文件内容
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 输出每一行内容
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
浙公网安备 33010602011771号