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();

        }

    }

}

posted on 2024-10-14 20:35  Daniel350  阅读(103)  评论(0)    收藏  举报