目录

创建 HDFS 目录

目录存在性判断

列出目录中的内容

删除目录

创建文件

文件存在性判断

文件写

文件读

文件重命名

文件删除

作业 


// 导入 Hadoop 的 Configuration 类,用于加载配置(用来告诉程序如何连接 HDFS)
import org.apache.hadoop.conf.Configuration;

// 导入 Hadoop 的 FileSystem 类,提供对文件系统的操作
import org.apache.hadoop.fs.FileSystem;

// 定义一个公共类 FileExist,程序入口类
public class FileExist {

    // 主函数,Java 程序执行的入口
    public static void main(String[] args) {
        try {
            // 创建 Configuration 对象,会自动读取 Hadoop 的配置文件
            // 默认读取位置是 $HADOOP_HOME/etc/hadoop 目录下的 core-site.xml 等配置文件
            Configuration conf = new Configuration();

            // 通过配置对象获取 FileSystem 实例
            // 如果配置文件中指定的是 HDFS 地址(如 hdfs://namenode:9000),则返回的是 HDFS 实例
            FileSystem fs = FileSystem.get(conf);


        } catch (Exception e) {
            // 如果在配置、连接文件系统等过程中出现异常,会被捕获到这里
            // 打印异常的堆栈信息,方便调试错误
            e.printStackTrace();
        }
    }
}

连接 Hadoop 的文件系统(HDFS)

FileSystem 类,是 Hadoop 提供的统一的文件系统抽象类,支持 HDFS、本地文件系统等。通过它可以进行文件的读取、写入、删除、检查是否存在等操作。


启动Hadoop 集群环境 

(master) > bash /scripts/hadoop/start-hadoop.sh

(master) >是终端或命令行的提示符(prompt)

意思是你当前所在的是 主节点master

本身不是命令,只是提示符的一部分

bash /scripts/hadoop/start-hadoop.sh

用 bash 执行一个叫 start-hadoop.sh 的 shell 脚本,路径是 /scripts/hadoop/start-hadoop.sh

Shell 脚本 就是一种写在文件里的“命令集合”,让你可以批量自动执行一堆命令,相当于给电脑写的“任务清单”

Shell命令行解释器

bash ---Bourne Again Shell,是 Linux 和 macOS 等操作系统中默认的 命令行解释器

Shell 是一个统称,bash 是最常用的一种 Shell


 使用 IntelliJ IDEA 创建一个用于开发 Hadoop HDFS 程序的 Java 工程


创建 HDFS 目录

CreateDir 类的功能是:
根据用户输入的目录路径,在 HDFS 上创建对应目录

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.util.Scanner;
import java.net.URI;

public class CreateDir {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in);
            String dirPath = '/'+sc.next();
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
            Path hdfsPath = new Path(dirPath);
            if(fs.mkdirs(hdfsPath)){
                System.out.println("Directory "+ dirPath +" has been created successfully!");
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}

程序所需的库:

  • Configuration:Hadoop 的配置类------用来加载 Hadoop 的配置信息,不写这个,后面就无法配置和连接 HDFS

  • FileSystem:HDFS 的客户端接口,操作文件系统----Java 和 HDFS 之间的“桥梁”

  • Path:代表 HDFS 路径的对象-----HDFS 路径必须用这个 Path 类来表示,不能用普通的字符串

  • Scanner:获取用户输入--Java 自带的输入类

  • URI:统一资源标识符,用来描述 Hadoop 的主节点地址

main 方法中 try-catch,用于捕获异常

public static void main(String[] args)-----Java 程序的主入口,程序从这里开始执行

Scanner sc = new Scanner(System.in);

创建一个扫描器,从控制台读取用户输入

String dirPath = "/" + sc.next();  // 字符串拼接

一个标准的 HDFS 路径

FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());

获取一个 HDFS 文件系统对象 fs,并且使它能够与 Hadoop 集群中的 HDFS 进行交互

FileSystem 是一个 Hadoop API 中的类,代表了一个文件系统。它定义了和文件系统交互的各种方法,例如上传、下载文件、创建目录、删除文件等操作。

  • "hdfs://master:9000":HDFS 的主节点地址(master 是主机名)。 Hadoop 启动后暴露给客户端的访问地址。new URI(...) 是用来创建一个 URI 对象,URI 是统一资源标识符(Uniform Resource Identifier)的缩写,用来标识一个资源的位置。在这里,URI 用来标识 Hadoop 集群中的 HDFS 地址

  • new Configuration():创建 Hadoop 的配置对象,加载默认配置

FileSystem.get()静态方法,用来获取一个 FileSystem 实例(对象)。这个方法的作用是:通过指定 URI 和 Hadoop 配置来建立与 HDFS 的连接

Path hdfsPath = new Path(dirPath);

将路径封装为 Path 对象--------HDFS 的 API 都需要传 Path 对象,而不是字符串

public boolean mkdirs(Path f) throws IOException

  • public:这是一个公开的方法,外部代码可以调用。

  • boolean:返回值是布尔类型 —— true 表示创建成功,false 表示失败。

  • mkdirs:方法名,意思是“创建目录”(make directories)。

  • Path f:传入的参数是一个 Hadoop 的 Path 对象,表示要创建的目录路径。

  • throws IOException:可能会抛出 IO 异常,比如 HDFS 无法连接、路径非法等

if(fs.mkdirs(hdfsPath)){
    System.out.println("Directory "+ dirPath +" has been created successfully!");
}
  • fs.mkdirs() 方法创建目录。

  • mkdirs() 不仅可以创建目录,还可以自动创建不存在的父目录(递归创建)


目录存在性判断

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.util.Scanner;
import java.net.URI;

public class DirExist {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in);
            String dirName = '/'+sc.next();
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
            if(fs.exists(new Path(dirName ))) {
                System.out.println("Directory Exists!");
            } else {
                System.out.println("Directory not Exists!");
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}

exists 方法用于检查指定的路径是否存在

  • new Path(dirName) 将用户输入的目录路径转换成 Hadoop 的 Path 对象。

  • fs.exists(new Path(dirName)) 检查该路径在 HDFS 上是否存在。


列出目录中的内容

listStatus 方法---该方法用于列出指定目录下的所有文件和子目录的详细信息

Path f:参数 f 是一个 Path 对象,表示你要查看的目录路径

返回值 FileStatus[]:方法返回一个 FileStatus 数组,FileStatus 对象封装了目录下每个文件或子目录的详细信息

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class ListFiles {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in);
            String filePath = sc.next();  // 读取用户输入的目录路径
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());  // 获取 FileSystem 对象
            Path srcPath = new Path(filePath);  // 创建指定路径的 Path 对象
            FileStatus[] stats = fs.listStatus(srcPath);  // 列出该目录下所有文件/子目录的 FileStatus 数组
            Path[] paths = FileUtil.stat2Paths(stats);  // 将 FileStatus 转换为 Path 数组
            for (Path p : paths)  // 遍历并输出每个文件或子目录的名称
                System.out.println(p.getName());  // 输出文件/子目录的名称
        } catch (Exception e) {
            e.printStackTrace();  // 异常处理
        }
    }
}

相关类

FileStatus:表示文件或目录的详细信息

FileUtil:工具类,包含一些有用的静态方法

用户输入的路径会存储在 filePath 变量中

sc.next() 是使用 Scanner 类来读取用户输入的一种方式。具体来说,next() 方法用于获取用户输入的下一个完整的单词(以空格、换行等为分隔符)。

sc.next() 会读取第一个“词”

调用 fs.listStatus() 方法获取指定路径下的所有文件和子目录的 FileStatus 数组

FileUtil.stat2Paths() 方法将 FileStatus 数组转换为 Path 数组。这样,我们就可以通过 Path 数组来进一步操作和输出文件/目录的路径

for (Path p : paths)
    System.out.println(p.getName());

使用 for 循环遍历 Path[] 数组,调用 getName() 方法输出每个文件或子目录的名称


删除目录

delete(Path f, boolean recursive):该方法用于删除 HDFS 上的文件或目录

  • f:表示要删除的文件或目录的路径,类型为 Path 对象。

  • recursive:这是一个布尔值。true 表示如果要删除的是一个目录,并且该目录中有子文件或子目录,则递归删除所有内容。false 表示仅删除目录本身(前提是目录为空),如果目录非空,删除操作将失败

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class DeleteDir {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in);
            String dirPath = '/' + sc.next();  // 读取用户输入的目录路径
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());  // 获取 HDFS 文件系统实例
            Path hdfsPath = new Path(dirPath);  // 创建 Path 对象,表示目录路径
            if (fs.delete(hdfsPath, true)) {  // 删除目录,递归删除目录中的内容
                System.out.println("Directory " + dirPath + " has been deleted successfully!");
            }
        } catch (Exception e) {
            e.printStackTrace();  // 异常处理
        }
    }
}


创建文件

create 方法主要用于在 HDFS 上创建文件。不同的重载方法具有不同的参数,可以控制文件创建时的行为,比如是否覆盖、使用的缓冲区大小、块大小、是否报告进度、设置副本数量等

各种重载方法及其参数说明:

public FSDataOutputStream create(Path f) throws IOException

根据给定路径 f 创建一个文件。如果文件已存在,会抛出异常

f:文件的路径。

返回值:返回一个 FSDataOutputStream 对象,可以用来写入数据。

public FSDataOutputStream create(Path f, boolean overwrite) throws IOException

根据路径 f 创建文件,overwrite 参数指定如果文件已存在,是否覆盖。

overwrite:如果 true,文件已存在则覆盖;如果 false,则不覆盖,抛出异常。

public FSDataOutputStream create(Path f, Progressable progress) throws IOException

创建文件并在创建过程中报告进度。

progress:一个 Progressable 对象,用于报告文件创建进度。

返回值:返回一个 FSDataOutputStream 对象。

public FSDataOutputStream create(Path f, short replication) throws IOException

创建文件,并设置文件的副本数量。

replication:文件块的副本数量

public FSDataOutputStream create(Path f, short replication, Progressable progress) throws IOException

创建文件,设置副本数量,并报告文件创建进度。

replication:文件副本数量。

progress:用于报告进度的 Progressable 对象。

public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize) throws IOException

创建文件,设置是否覆盖,以及缓冲区大小。

overwrite:是否覆盖已存在的文件。

bufferSize:缓冲区的大小。

public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize, Progressable progress) throws IOException

创建文件,设置是否覆盖、缓冲区大小,并报告进度。

overwrite:是否覆盖已存在的文件。

bufferSize:缓冲区大小。

progress:报告进度的 Progressable 对象。

public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize, short replication, long blockSize) throws IOException

创建文件,设置是否覆盖、缓冲区大小、副本数量和块大小。

overwrite:是否覆盖已存在的文件。

bufferSize:缓冲区大小。

replication:文件副本数量。

blockSize:文件的块大小。

public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException

创建文件,设置是否覆盖、缓冲区大小、副本数量、块大小,并报告进度。

overwrite:是否覆盖已存在的文件。

bufferSize:缓冲区大小。

replication:文件副本数量。

blockSize:文件块大小。

progress:报告进度的 Progressable 对象

public abstract FSDataOutputStream create(Path f, FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException

创建文件,并设置文件权限、是否覆盖、缓冲区大小、副本数量、块大小、以及进度报告。

permission:文件的权限设置。

overwrite:是否覆盖已存在的文件。

bufferSize:缓冲区大小。

replication:副本数量。

blockSize:块大小。

progress:报告进度的 Progressable 对象。

public FSDataOutputStream create(Path f, FsPermission permission, EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException

创建文件,设置权限、文件创建标志、缓冲区大小、副本数量、块大小和进度报告。

permission:文件权限。

flags:文件创建标志。

bufferSize:缓冲区大小。

replication:副本数量。

blockSize:块大小。

progress:报告进度的 Progressable 对象。

public FSDataOutputStream create(Path f, FsPermission permission, EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize, Progressable progress, Options.ChecksumOpt checksumOpt) throws IOException

创建文件,设置权限、文件创建标志、缓冲区大小、副本数量、块大小、进度报告以及校验和选项。

permission:文件权限。

flags:文件创建标志。

bufferSize:缓冲区大小。

replication:副本数量。

blockSize:块大小。

progress:报告进度的 Progressable 对象。

checksumOpt:校验和选项

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class CreateFile {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in); // 1. 创建Scanner对象,用于读取用户输入
            String filePath = '/'+sc.next(); // 2. 获取用户输入的文件路径,并加上前缀‘/’构成完整路径
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration()); // 3. 获取HDFS文件系统实例
            Path hdfsPath = new Path(filePath); // 4. 创建Path对象,表示文件的路径
            fs.create(hdfsPath); // 5. 使用FileSystem实例在HDFS上创建文件
        } catch (Exception e) { // 6. 异常处理
            e.printStackTrace(); // 输出异常信息
        }
    }
}

文件存在性判断

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class FileExist {
    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in); // 1. 创建Scanner对象,用于读取用户输入
            String fileName = '/'+sc.next(); // 2. 获取用户输入的文件路径,并加上前缀‘/’构成完整路径
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration()); // 3. 获取HDFS文件系统实例
            if (fs.exists(new Path(fileName))) { // 4. 判断文件是否存在
                System.out.println("File Exists!"); // 5. 如果文件存在,输出提示信息
            } else {
                System.out.println("File not Exists!"); // 6. 如果文件不存在,输出提示信息
            }
        } catch (Exception e) { // 7. 异常处理
            e.printStackTrace(); // 输出异常信息
        }
    }
}

FileSystem.exists(Path f) 方法,判断文件路径所指向的文件是否存在

exists() 方法会返回一个布尔值。如果路径所指向的文件存在,返回 true;否则返回 false


文件写

HDFS 不支持文件的随机写操作,只能顺序写入数据

  • 创建文件并写入数据:使用 create() 方法创建文件并将数据写入文件。如果文件已存在,可以选择覆盖或追加。

  • 文件已存在,追加数据:使用 append() 方法将数据追加到文件的尾部

FileSystem.create() 方法

  • public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize, short replication, long blockSize)

  • 如果文件不存在,则创建文件并返回一个输出流 FSDataOutputStream。如果文件已经存在,可以选择是否覆盖。overwrite: 是否覆盖已存在的文件(true 表示覆盖)。

    • bufferSize: 缓冲区大小,单位是字节。

    • replication: 文件的副本数量,通常设为1。

    • blockSize: 文件块的大小,这里用 1 << 26(即64MB)来设置块大小。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class WriteFile {
    public static void main(String[] args) {
        try {
            // 创建Scanner对象,用于从控制台读取输入
            Scanner sc = new Scanner(System.in);
            // 获取用户输入的文件路径,并为其加上前缀'/',使其成为绝对路径
            String filePath = '/'+sc.next();

            // 获取HDFS文件系统的实例
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());

            // 创建Path对象,表示文件的路径
            Path srcPath = new Path(filePath);

            // 第一部分:使用create方法创建文件并写入数据
            FSDataOutputStream os = fs.create(srcPath, true, 1024, (short) 1, (long)(1 << 26));  // 创建文件,返回输出流
            String str = "Hello, this is a sentence that should be written into the file.\n"; // 待写入文件的字符串
            os.write(str.getBytes());  // 将字符串写入文件
            os.flush();  // 将内存中的数据刷新到文件
            os.close();  // 关闭流,完成文件的写入

            // 第二部分:使用append方法向已有文件中追加数据
            os = fs.append(srcPath);  // 打开文件,并定位到文件尾部
            str = "Hello, this is another sentence that should be written into the file.\n";  // 待追加的字符串
            os.write(str.getBytes());  // 将字符串写入文件
            os.flush();  // 将内存中的数据刷新到文件
            os.close();  // 关闭流,完成数据的追加
        } catch (Exception e) {
            e.printStackTrace();  // 捕获并打印异常
        }
    }
}

FSDataOutputStream.write() 方法

将字节数组写入文件。os.write(str.getBytes()) 会将字符串 str 转换为字节数组,并将其写入文件。

FSDataOutputStream.flush() 方法

将内存中缓冲的数据刷新到磁盘上。通常在写入数据后调用此方法,以确保数据写入文件系统。

FSDataOutputStream.close() 方法

关闭流,释放资源。每次完成写操作后,应该调用 close() 来确保文件写操作的完成。


文件读

FileSystem.open() 方法

public FSDataInputStream open(Path f) throws IOException

打开指定路径的文件,返回一个 FSDataInputStream 对象,可以利用该对象读取文件的内容。

FSDataInputStream.readLine() 方法

逐行读取文件内容。每次调用 readLine(),返回的是文件的一行内容。若没有更多内容,返回 null

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;
import java.util.Scanner;

public class ReadFile {
    public static void main(String[] args) {
        try {
            // 创建Scanner对象,读取用户输入的文件路径
            Scanner sc = new Scanner(System.in);
            String filePath = '/'+sc.next();  // 获取用户输入的文件路径,路径前加上'/'

            // 获取HDFS文件系统的实例
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
            
            // 创建Path对象,表示HDFS中文件的路径
            Path srcPath = new Path(filePath);

            // 使用open方法打开文件,返回一个FSDataInputStream对象
            FSDataInputStream is = fs.open(srcPath);
            
            // 循环读取文件内容,直到文件末尾
            while (true) {
                String line = is.readLine();  // 逐行读取
                if (line == null) {  // 如果读取到文件末尾,则退出循环
                    break;
                }
                System.out.println(line);  // 打印每一行
            }

            // 关闭输入流
            is.close();
        } catch (Exception e) {
            e.printStackTrace();  // 捕获异常并打印堆栈信息
        }
    }
}

文件重命名

public abstract boolean rename(Path src, Path dst) throws IOException

rename将路径 src (原始路径)重命名为路径 dst(目标路径
 

import org.apache.hadoop.conf.Configuration; // 导入Hadoop的配置类
import org.apache.hadoop.fs.FileSystem;      // 导入HDFS文件系统类
import org.apache.hadoop.fs.Path;            // 导入Path类,用于表示HDFS路径

import java.net.URI;                         // 导入URI类,用于定位HDFS路径
import java.util.Scanner;                    // 导入Scanner类,用于接收用户输入

public class Rename {
    public static void main(String[] args) {
        try {
            // 创建Scanner对象,从控制台读取用户输入
            Scanner sc = new Scanner(System.in);

            // 从控制台读取源文件名,并加上'/'构造成HDFS中的绝对路径
            String srcStrPath = '/' + sc.next(); // 例如输入 oldfile.txt,结果为 /oldfile.txt

            // 从控制台读取目标文件名,并加上'/'构造成HDFS中的绝对路径
            String dstStrPath = '/' + sc.next(); // 例如输入 newfile.txt,结果为 /newfile.txt

            // 创建FileSystem对象,连接到HDFS(这里使用的是主机名为master,端口为9000)
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());

            // 构造源路径和目标路径的Path对象
            Path srcPath = new Path(srcStrPath);
            Path dstPath = new Path(dstStrPath);

            // 使用rename方法进行文件重命名操作
            if (fs.rename(srcPath, dstPath)) {
                // 如果重命名成功,输出提示信息
                System.out.println("rename from " + srcStrPath + " to " + dstStrPath + " successfully!");
            } else {
                // 如果重命名失败,输出失败提示
                System.out.println("Failed to rename " + srcStrPath + " to " + dstStrPath);
            }
        } catch (Exception e) {
            // 捕获并打印所有异常信息,避免程序崩溃
            e.printStackTrace();
        }
    }
}


文件删除

public abstract boolean delete(Path f, boolean recursive) throws IOException

删除 HDFS 中的文件或目录

recursive:是否递归删除(若是目录且非空,必须为 true

import org.apache.hadoop.conf.Configuration; // 导入Hadoop配置类
import org.apache.hadoop.fs.FileSystem;      // 导入HDFS文件系统类
import org.apache.hadoop.fs.Path;            // 导入路径类

import java.net.URI;                         // 导入URI类,用于表示HDFS地址
import java.util.Scanner;                    // 导入Scanner类,用于接收用户输入

public class DeleteFile {
    public static void main(String[] args) {
        try {
            // 创建Scanner对象,用于从控制台读取用户输入的文件路径
            Scanner sc = new Scanner(System.in);

            // 从控制台读取要删除的文件路径,并加上前缀'/'构成HDFS根目录下路径
            String filePath = '/' + sc.next();

            // 创建FileSystem对象,连接HDFS(master为主节点,端口9000)
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());

            // 创建Path对象,表示要删除的HDFS路径
            Path hdfsPath = new Path(filePath);

            // 调用delete方法删除文件
            // 第二个参数false表示非递归删除(即不能删除非空目录)
            if (fs.delete(hdfsPath, false)) {
                System.out.println("File " + filePath + " has been deleted successfully!");
            } else {
                System.out.println("Failed to delete file " + filePath + ". It may not exist.");
            }
        } catch (Exception e) {
            // 捕获并打印异常信息
            e.printStackTrace();
        }
    }
}

删除目录且目录非空,第二个参数必须设为 true



作业 

  • Configuration:配置文件(连接 HDFS 用)

  • FileSystem:代表 HDFS 文件系统对象

  • Path:代表 HDFS 或本地文件路径

  • FileStatus:描述文件或目录的状态信息

连接到 HDFS 文件系统

创建 Scanner 对象,从控制台接收用户输入

进入一个无限循环,不停接收用户输入

读取用户输入的第一个单词(比如 HShell

判断用户是不是输入了 HShell,如果是,继续解析后面的命令

读取第二个单词,比如 -cp-rm 等操作

如果输入 -r,表示要复制目录,使用 copyFromLocalFile 拷贝整个目录到HDFS

否则就是普通的拷贝文件操作

-rm 删除文件或目录,如果是 -r,说明是要递归删除目录,

fs.delete(path, true)true代表递归删除。则删除的是单个文件,不递归

-list 查看路径信息。显示某个路径(文件或目录)的详细信息

fs.exists(Path) 方法:检查 HDFS 上是否真的存在这个路径:存在,继续查询
。如果不存在,提示路径不存在

FileStatus status = fs.getFileStatus(new Path(path));

  • 调用 fs.getFileStatus(Path) 方法,获取指定文件或目录的详细信息

  • 返回的是一个 FileStatus 对象,里面包含了很多属性

    • 是文件还是目录

    • 文件大小

    • 权限(rwx)

    • 所有者。。。。。。。

FileStatus 就像一个文件的身份证,记录了所有关键信息。

FileStatus 对象的 toString() 方法,打印出文件/目录的所有信息 

-mv 移动或重命名

将源路径 src 移动或重命名到目标路径 dst。使用 fs.rename() 方法

-find 递归查找文件

递归搜索HDFS目录下,是否存在目标文件名。

调用下面定义的 findFile() 方法

如果当前是目录,递归进入子目录继续找。如果是文件,检查名字是否匹配。找到目标文件时,输出路径

私有静态方法private static),只能在本类中调用

FileSystem fs :已经连接好的 HDFS 文件系统对象

Path dir :当前需要搜索的目录路径

String filename :要查找的文件名
调用 fs.exists(dir)检查指定目录是否存在。

调用 fs.listStatus(dir) 获取当前目录下的所有子文件和子目录的状态列表

遍历每一个子文件/子目录

如果遇到子目录,递归查找

如果是文件,判断名字是否匹配

关闭Scanner(释放输入流)

关闭FileSystem连接(释放资源)

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.net.URI;
import java.util.Scanner;

public class HShell {
    public static void main(String[] args) {
        try {
            // 连接HDFS(根据自己环境修改URI)
            FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration(), "hadoop");
            Scanner sc = new Scanner(System.in);

            System.out.println("欢迎使用HShell,输入命令开始操作:");

            while (true) {
                System.out.print("> "); // 提示符
                String cmd = sc.next();

                if (cmd.equals("HShell")) {
                    String option = sc.next();

                    if (option.equals("-cp")) {
                        String src = sc.next();
                        String dst = sc.next();
                        if (src.equals("-r")) {
                            // 拷贝目录
                            String localDir = dst;
                            String hdfsDst = sc.next();
                            fs.copyFromLocalFile(false, true, new Path(localDir), new Path(hdfsDst));
                            System.out.println("目录拷贝成功: " + localDir + " -> " + hdfsDst);
                        } else {
                            // 拷贝文件
                            fs.copyFromLocalFile(new Path(src), new Path(dst));
                            System.out.println("文件拷贝成功: " + src + " -> " + dst);
                        }
                    } else if (option.equals("-rm")) {
                        String path = sc.next();
                        if (path.equals("-r")) {
                            // 删除目录
                            String dir = sc.next();
                            if (fs.delete(new Path(dir), true)) {
                                System.out.println("目录删除成功: " + dir);
                            } else {
                                System.out.println("目录删除失败: " + dir);
                            }
                        } else {
                            // 删除文件
                            if (fs.delete(new Path(path), false)) {
                                System.out.println("文件删除成功: " + path);
                            } else {
                                System.out.println("文件删除失败: " + path);
                            }
                        }
                    } else if (option.equals("-list")) {
                        String path = sc.next();
                        FileStatus status = fs.getFileStatus(new Path(path));
                        System.out.println("路径信息:");
                        System.out.println(status.toString());
                    } else if (option.equals("-mv")) {
                        String src = sc.next();
                        String dst = sc.next();
                        if (fs.rename(new Path(src), new Path(dst))) {
                            System.out.println("移动/重命名成功: " + src + " -> " + dst);
                        } else {
                            System.out.println("移动/重命名失败: " + src);
                        }
                    } else if (option.equals("-find")) {
                        String fileName = sc.next();
                        String dirPath = sc.next();
                        findFile(fs, new Path(dirPath), fileName);
                    } else {
                        System.out.println("无效的操作,请重新输入!");
                    }
                } else if (cmd.equals("exit")) {
                    System.out.println("退出HShell,再见!");
                    break;
                } else {
                    System.out.println("命令应以 HShell 开头!");
                }
            }
            sc.close();
            fs.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 辅助方法:递归查找文件
    private static void findFile(FileSystem fs, Path path, String targetName) throws Exception {
        FileStatus[] statuses = fs.listStatus(path);
        for (FileStatus status : statuses) {
            if (status.isDirectory()) {
                // 递归子目录
                findFile(fs, status.getPath(), targetName);
            } else {
                if (status.getPath().getName().equals(targetName)) {
                    System.out.println("找到文件: " + status.getPath().toString());
                }
            }
        }
    }
}

可以改成switch更好

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐