实验二 熟悉HDFS常用操作

实验目的:

  1. 理解HDFS在Hadoop体系结构中的角色。

  2. 熟练使用HDFS操作常用的Shell命令。

  3. 熟悉HDFS操作常用的Java API。

实验环境:

  1. Oracle VM VirtualBox虚拟机

  2. 系统版本Ubuntu 18.04 64

  3. JDK1.8版本

  4. Hadoop-3.1.3

  5. Windows11

  6. Java IDE:Eclipse

实验内容与完成情况:

1. 利用Hadoop提供的Shell命令完成下列任务

前期:

先启动hadoop:

cd /usr/local/hadoop
./sbin/start-dfs.sh

运行结果截图:

创建text.txt文件:

cd ~
echo "Hello World!" >text.txt

运行结果截图:

在Ubuntu中安装Eclipse:

Eclipse是常用的程序开发工具,本教程很多程序代码都是使用Eclipse开发调试,因此,需要在Linux系统中安装Eclipse。

可以到Eclipse官网(Eclipse Downloads | The Eclipse Foundation)下载安装包。 ​ 或者直接点击这里从百度云盘下载软件(提取码:lnwl),位于“软件”目录下,文件名eclipse-4.7.0-linux.gtk.x86_64.tar.gz。假设安装文件下载后保存在了Linux系统的目录“~/Downloads”下,下面执行如下命令对文件进行解压缩:

cd ~/Downloads
sudo tar -zxvf ./eclipse-4.7.0-linux.gtk.x86_64.tar.gz -C /usr/local 

运行结果截图:

然后,执行如下命令启动Eclipse:

cd /usr/local/eclipse
./eclipse 

这时,就可以看到Eclipse的启动界面了。

启动Eclipse。当Eclipse启动以后,会弹出如下图所示界面,提示设置工作空间:

可以直接采用默认的设置“/home/hadoop/workspace”,点击“OK”按钮。可以看出,由于当前是采用hadoop用户登录了Linux系统,因此,默认的工作空间目录位于hadoop用户目录”/home/ hadoop”下

Eclipse启动以后,会呈现如下图所示的界面:

选择“File-->New-->Java Project”菜单,开始创建一个Java工程,会弹出如下图所示界面:

在“Project name”后面输入工程名称“HDFSExample”,选中“Use default location”,让这个Java工程的所有文件都保存到“/home/hadoop/workspace/HDFSExample”目录下。在“JRE”这个选项卡中,可以选择当前的Linux系统中已经安装好的JDK,比如jdk1.8.0_162。然后,点击界面底部的“Next>”按钮,进入下一步的设置。

进入下一步的设置以后,会弹出如下图所示界面:

需要在这个界面中加载该Java工程所需要用到的JAR包,这些JAR包中包含了可以访问HDFS的Java API。这些JAR包都位于Linux系统的Hadoop安装目录下,对于本教程而言,就是在“/usr/local/hadoop/share/hadoop”目录下。点击界面中的“Libraries”选项卡,然后,点击界面右侧的“Add External JARs…”按钮,会弹出如下图所示界面:

在该界面中,上面的一排目录按钮(即“usr”、“local”、“hadoop”、“share”、“hadoop”和“common”),当点击某个目录按钮时,就会在下面列出该目录的内容。 ​ 为了编写一个能够与HDFS交互的Java应用程序,一般需要向Java工程中添加以下JAR包: ​ 1)“/usr/local/hadoop/share/hadoop/common”目录下的所有JAR包,包括hadoop- common-3.1.3.jar、hadoop-common-3.1.3-tests.jar、haoop-nfs-3.1.3.jar和haoop-kms-3.1.3.jar,注意,不包括目录jdiff、lib、sources和webapps; ​ 2)“/usr/local/hadoop/share/hadoop/common/lib”目录下的所有JAR包; ​ 3)“/usr/local/hadoop/share/hadoop/hdfs”目录下的所有JAR包,注意,不包括目录jdiff、lib、sources和webapps; ​ 4)“/usr/local/hadoop/share/hadoop/hdfs/lib”目录下的所有JAR包。 ​

新建一个java类,至此,eclipse安装完成。

  • (1)向HDFS中上传任意文本文件,如果指定的文件在HDFS中已经存在,由用户指定是追加到原有文件末尾还是覆盖原有的文件。

    Shell 命令

    检查文件是否存在,可以使用如下命令

$ cd /usr/local/hadoop
$ ./bin/hdfs dfs -test -e text.txt

执行完上述命令不会输出结果,需要继续输入命令查看结果:

$ echo $?

运行结果截图:

如果结果显示文件已经存在,则用户可以选择追加到原来文件末尾或者覆盖原来文件,

具体命令如下:

$ cd /usr/local/hadoop
$ ./bin/hdfs dfs -appendToFile local.txt text.txt #追加到原文件末尾
$ ./bin/hdfs dfs -copyFromLocal -f local.txt text.txt #覆盖原来文件,第一种命令形式
$ ./bin/hdfs dfs -cp -f file:///home/hadoop/local.txt text.txt #覆盖原来文件,第二种命令形式

运行结果截图:

实际上,也可以不用上述方式,而是采用如下命令来实现:

$ if $(hdfs dfs -test -e text.txt);
$ then $(hdfs dfs -appendToFile local.txt text.txt);
$ else $(hdfs dfs -copyFromLocal -f local.txt text.txt);
$ fi

上述代码可视为一行代码,在终端中输入第一行代码后,代码不会立即被执行,可以继续输入第 2 行代码和第 3 行代码,直到输入 fi 以后,上述代码才会真正执行。另外,上述代码中,直接使用了 hdfs 命令,而没有给出命令的路径,因为,这里假设已经配置了 PATH环境变量,把 hdfs 命令的路径“/usr/local/hadoop/bin”写入了 PATH 环境变量中

Java 代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 判断路径是否存在
 */
 public static boolean test(Configuration conf, String path) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 return fs.exists(new Path(path));
 }
 /**
 * 复制文件到指定路径
 * 若路径已存在,则进行覆盖
 */
 public static void copyFromLocalFile(Configuration conf, String localFilePath, String 
remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path localPath = new Path(localFilePath);
 Path remotePath = new Path(remoteFilePath);
 /* fs.copyFromLocalFile 第一个参数表示是否删除源文件,第二个参数表示是否覆
盖 */
 fs.copyFromLocalFile(false, true, localPath, remotePath);
 fs.close();
 }
 /**
 * 追加文件内容
 */
 public static void appendToFile(Configuration conf, String localFilePath, String 
remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 /* 创建一个文件读入流 */
 FileInputStream in = new FileInputStream(localFilePath);
 /* 创建一个文件输出流,输出的内容将追加到文件末尾 */
 FSDataOutputStream out = fs.append(remotePath);
 /* 读写文件内容 */
 byte[] data = new byte[1024];
 int read = -1;
 while ( (read = in.read(data)) > 0 ) {
 out.write(data, 0, read);
 }
 out.close();
 in.close();
 fs.close();
 }
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String localFilePath = "/home/hadoop/text.txt"; // 本地路径
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 路径
String choice = "append"; // 若文件存在则追加到文件末尾
// String choice = "overwrite"; // 若文件存在则覆盖
try {
/* 判断文件是否存在 */
Boolean fileExists = false;
if (HDFSApi.test(conf, remoteFilePath)) {
fileExists = true;
System.out.println(remoteFilePath + " 已存在.");
} else {
System.out.println(remoteFilePath + " 不存在.");
}
​
/* 进行处理 */
if ( !fileExists) { // 文件不存在,则上传
HDFSApi.copyFromLocalFile(conf, localFilePath, remoteFilePath);
System.out.println(localFilePath + " 已上传至 " + remoteFilePath);
} else if ( choice.equals("overwrite") ) { // 选择覆盖
HDFSApi.copyFromLocalFile(conf, localFilePath, remoteFilePath);
System.out.println(localFilePath + " 已覆盖 " + remoteFilePath);
} else if ( choice.equals("append") ) { // 选择追加
HDFSApi.appendToFile(conf, localFilePath, remoteFilePath);
System.out.println(localFilePath + " 已追加至 " + remoteFilePath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (2)从HDFS中下载指定文件,如果本地文件与要下载的文件名称相同,则自动对下载的文件重命名

    Shell命令

$ if $(hdfs dfs -test -e file:///home/hadoop/text.txt)
$ then $(hdfs dfs -copyToLocal text.txt ./text2.txt)
$ else $(hdfs dfs -copyToLocal text.txt ./text.txt)
$ fi

运行结果截图:

Java 代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 下载文件到本地
 * 判断本地路径是否已存在,若已存在,则自动进行重命名
 */
 public static void copyToLocal(Configuration conf, String remoteFilePath, String 
localFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 File f = new File(localFilePath);
 /* 如果文件名存在,自动重命名(在文件名后面加上 _0, _1 ...) */
 if (f.exists()) {
 System.out.println(localFilePath + " 已存在.");
 Integer i = 0;
​
 while (true) {
 f = new File(localFilePath + "_" + i.toString());
 if (!f.exists()) {
 localFilePath = localFilePath + "_" + i.toString();
 break;
 }
 }
 System.out.println("将重新命名为: " + localFilePath);
 }
 
 // 下载文件到本地
 Path localPath = new Path(localFilePath);
 fs.copyToLocalFile(remotePath, localPath);
 fs.close();
 }
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String localFilePath = "/home/hadoop/text.txt"; // 本地路径
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 路径
try {
HDFSApi.copyToLocal(conf, remoteFilePath, localFilePath);
System.out.println("下载完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (3)将HDFS中指定文件的内容输出到终端中。

    Shell命令

    $ hdfs dfs -cat text.txt

    运行结果截图:

  • Java 代码
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.*;
    import java.io.*;
    ​
    public class HDFSApi {
     /**
     * 读取文件内容
     */
     public static void cat(Configuration conf, String remoteFilePath) throws IOException {
     FileSystem fs = FileSystem.get(conf);
     Path remotePath = new Path(remoteFilePath);
     FSDataInputStream in = fs.open(remotePath);
     BufferedReader d = new BufferedReader(new InputStreamReader(in));
     String line = null;
     while ( (line = d.readLine()) != null ) {
     System.out.println(line);
     }
     d.close();
     in.close();
     fs.close();
     }
     
    /**
    * 主函数
    */
    public static void main(String[] args) {
    Configuration conf = new Configuration();
     conf.set("fs.default.name","hdfs://localhost:9000");
    String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 路径
    try {
    System.out.println("读取文件: " + remoteFilePath);
    HDFSApi.cat(conf, remoteFilePath);
    System.out.println("\n 读取完成");
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    运行结果截图:

  • (4)显示HDFS中指定的文件的读写权限、大小、创建时间、路径等信息;执行下列命令。

Shell命令

hdfs dfs -ls -h text.txt

运行结果截图:

Java 代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
import java.text.SimpleDateFormat;
public class HDFSApi {
 /**
 * 显示指定文件的信息
 */
 public static void ls(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 FileStatus[] fileStatuses = fs.listStatus(remotePath);
 for (FileStatus s : fileStatuses) {
 System.out.println("路径: " + s.getPath().toString());
 System.out.println("权限: " + s.getPermission().toString());
 System.out.println("大小: " + s.getLen());
 /* 返回的是时间戳,转化为时间日期格式 */
 Long timeStamp = s.getModificationTime();
 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 String date = format.format(timeStamp); 
 System.out.println("时间: " + date);
 }
 fs.close();
 }
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 路径
try {
System.out.println("读取文件信息: " + remoteFilePath);
HDFSApi.ls(conf, remoteFilePath);
System.out.println("\n 读取完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (5)给定HDFS中某一个目录,输出该目录下的所有文件的读写权限、大小、创建时间、路径等信息,如果该文件是目录,则递归输出该目录下所有文件相关信息。

Shell命令

$ cd /usr/local/hadoop
$ ./bin/hdfs dfs -ls -R -h /user/hadoop

运行结果截图:

Java 代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
import java.text.SimpleDateFormat;
public class HDFSApi {
 /**
 * 显示指定文件夹下所有文件的信息(递归)
 */
 public static void lsDir(Configuration conf, String remoteDir) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path dirPath = new Path(remoteDir);
 /* 递归获取目录下的所有文件 */
 RemoteIterator<LocatedFileStatus> remoteIterator = fs.listFiles(dirPath, true);
 /* 输出每个文件的信息 */
 while (remoteIterator.hasNext()) {
 FileStatus s = remoteIterator.next();
 System.out.println("路径: " + s.getPath().toString());
 System.out.println("权限: " + s.getPermission().toString());
 System.out.println("大小: " + s.getLen());
 /* 返回的是时间戳,转化为时间日期格式 */
 Long timeStamp = s.getModificationTime();
 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 String date = format.format(timeStamp); 
 System.out.println("时间: " + date);
 System.out.println();
 }
 fs.close();
 } 
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteDir = "/user/hadoop"; // HDFS 路径
try {
​
System.out.println("(递归)读取目录下所有文件的信息: " + remoteDir);
HDFSApi.lsDir(conf, remoteDir);
System.out.println("读取完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (6)提供一个HDFS内的文件的路径,对该文件进行创建和删除操作。如果文件所在目录不存在,则自动创建目录。

Shell命令

$ if $(hdfs dfs -test -d dir1/dir2)
$ then $(hdfs dfs -touchz dir1/dir2/filename)
$ else $(hdfs dfs -mkdir -p dir1/dir2 && hdfs dfs -touchz dir1/dir2/filename)
$ fi
$ hdfs dfs -rm dir1/dir2/filename #删除文件

运行结果截图:

Java代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 判断路径是否存在
 */
 public static boolean test(Configuration conf, String path) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 return fs.exists(new Path(path));
 }
 /**
 * 创建目录
 */
 public static boolean mkdir(Configuration conf, String remoteDir) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path dirPath = new Path(remoteDir);
 boolean result = fs.mkdirs(dirPath);
 fs.close();
 return result;
 }
 /**
 * 创建文件
 */
 public static void touchz(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 FSDataOutputStream outputStream = fs.create(remotePath);
 outputStream.close();
 fs.close();
 }
 
 /**
 * 删除文件
 */
 public static boolean rm(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 boolean result = fs.delete(remotePath, false);
 fs.close();
 return result;
 }
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/input/text.txt"; // HDFS 路径
String remoteDir = "/user/hadoop/input"; // HDFS 路径对应的目录
try {
/* 判断路径是否存在,存在则删除,否则进行创建 */
if ( HDFSApi.test(conf, remoteFilePath) ) {
HDFSApi.rm(conf, remoteFilePath); // 删除
System.out.println("删除路径: " + remoteFilePath);
} else {
if ( !HDFSApi.test(conf, remoteDir) ) { // 若目录不存在,则进行创建
HDFSApi.mkdir(conf, remoteDir);
System.out.println("创建文件夹: " + remoteDir);
}
HDFSApi.touchz(conf, remoteFilePath);
System.out.println("创建路径: " + remoteFilePath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (7)提供一个HDFS的目录的路径,对该目录进行创建和删除操作。创建目录时,如果目录文件所在目录不存在则自动创建相应目录;删除目录时,由用户指定当该目录不为空时是否还删除该目录。

Shell命令

创建目录的命令如下:

$ hdfs dfs -mkdir -p dir1/dir2

删除目录的命令如下:

$ hdfs dfs -rmdir dir1/dir2

上述命令执行以后,如果目录非空,则会提示 not empty,删除操作不会执行。如果要强制删除目录,可以使用如下命令:

$ hdfs dfs -rm -R dir1/dir2

运行结果截图:

Java代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 判断路径是否存在
 */
 public static boolean test(Configuration conf, String path) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 return fs.exists(new Path(path));
 }
 /**
 * 判断目录是否为空
 * true: 空,false: 非空
 */
 public static boolean isDirEmpty(Configuration conf, String remoteDir) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path dirPath = new Path(remoteDir);
 RemoteIterator<LocatedFileStatus> remoteIterator = fs.listFiles(dirPath, true);
 return !remoteIterator.hasNext();
​
 }
 /**
 * 创建目录
 */
 public static boolean mkdir(Configuration conf, String remoteDir) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path dirPath = new Path(remoteDir);
 boolean result = fs.mkdirs(dirPath);
 fs.close();
 return result;
 }
 
 /**
 * 删除目录
 */
 public static boolean rmDir(Configuration conf, String remoteDir) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path dirPath = new Path(remoteDir);
 /* 第二个参数表示是否递归删除所有文件 */
 boolean result = fs.delete(dirPath, true);
 fs.close();
 return result;
 }
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteDir = "/user/hadoop/input"; // HDFS 目录
Boolean forceDelete = false; // 是否强制删除
try {
/* 判断目录是否存在,不存在则创建,存在则删除 */
if ( !HDFSApi.test(conf, remoteDir) ) {
HDFSApi.mkdir(conf, remoteDir); // 创建目录
System.out.println("创建目录: " + remoteDir);
} else {
if ( HDFSApi.isDirEmpty(conf, remoteDir) || forceDelete ) { // 目录为空或强制删除
HDFSApi.rmDir(conf, remoteDir);
System.out.println("删除目录: " + remoteDir);
​
} else { // 目录不为空
System.out.println("目录不为空,不删除: " + remoteDir);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

因为已用Shell指令删除,故输出为目录不为空,不删除: /usr/hadoop/input

  • (8)向HDFS中指定的文件追加内容,由用户指定将内容追加到原有文件的开头或结尾。

Shell命令

追加到原文件末尾的命令如下:

$ hdfs dfs -appendToFile local.txt text.txt

追加到原文件的开头,在 HDFS 中不存在与这种操作对应的命令,因此,无法使用一条命令来完成。可以先移动到本地进行操作,再进行上传覆盖,具体命令如下:

$ hdfs dfs -get text.txt
$ cat text.txt >> local.txt
$ hdfs dfs -copyFromLocal -f text.txt text.txt

运行结果截图:

Java代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 判断路径是否存在
 */
 public static boolean test(Configuration conf, String path) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 return fs.exists(new Path(path));
 }
 /**
 * 追加文本内容
 */
 public static void appendContentToFile(Configuration conf, String content, String 
remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 /* 创建一个文件输出流,输出的内容将追加到文件末尾 */
​
 FSDataOutputStream out = fs.append(remotePath);
 out.write(content.getBytes());
 out.close();
 fs.close();
}
 /**
 * 追加文件内容
 */
 public static void appendToFile(Configuration conf, String localFilePath, String 
remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 /* 创建一个文件读入流 */
 FileInputStream in = new FileInputStream(localFilePath);
 /* 创建一个文件输出流,输出的内容将追加到文件末尾 */
 FSDataOutputStream out = fs.append(remotePath);
 /* 读写文件内容 */
 byte[] data = new byte[1024];
 int read = -1;
 while ( (read = in.read(data)) > 0 ) {
 out.write(data, 0, read);
 }
 out.close();
 in.close();
 fs.close();
 }
 /**
 * 移动文件到本地
 * 移动后,删除源文件
 */
 public static void moveToLocalFile(Configuration conf, String remoteFilePath, String 
localFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 Path localPath = new Path(localFilePath);
 fs.moveToLocalFile(remotePath, localPath);
 }
 
 /**
 * 创建文件
 */
 public static void touchz(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 FSDataOutputStream outputStream = fs.create(remotePath);
 outputStream.close();
 fs.close();
 }
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 文件
String content = "新追加的内容\n";
String choice = "after"; //追加到文件末尾
// String choice = "before"; // 追加到文件开头
try {
/* 判断文件是否存在 */
if ( !HDFSApi.test(conf, remoteFilePath) ) {
System.out.println("文件不存在: " + remoteFilePath);
} else {
if ( choice.equals("after") ) { // 追加在文件末尾
HDFSApi.appendContentToFile(conf, content, remoteFilePath);
System.out.println("已追加内容到文件末尾" + remoteFilePath);
} else if ( choice.equals("before") ) { // 追加到文件开头
/* 没有相应的 api 可以直接操作,因此先把文件移动到本地*/
/*创建一个新的 HDFS,再按顺序追加内容 */
String localTmpPath = "/user/hadoop/tmp.txt";
// 移动到本地
HDFSApi.moveToLocalFile(conf, remoteFilePath, localTmpPath);
 // 创建一个新文件
HDFSApi.touchz(conf, remoteFilePath); 
 // 先写入新内容
HDFSApi.appendContentToFile(conf, content, remoteFilePath);
 // 再写入原来内容
HDFSApi.appendToFile(conf, localTmpPath, remoteFilePath); 
System.out.println("已追加内容到文件开头: " + remoteFilePath);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

  • (9)删除HDFS中指定的文件。

Shell指令

$ hdfs dfs -rm text.txt

运行结果截图:

Java代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.*;
public class HDFSApi {
 /**
 * 删除文件
 */
 public static boolean rm(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 boolean result = fs.delete(remotePath, false);
 fs.close();
 return result;
 }
 
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 文件
try {
if ( HDFSApi.rm(conf, remoteFilePath) ) {
System.out.println("文件删除: " + remoteFilePath);
} else {
System.out.println("操作失败(文件不存在或删除失败)");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

因为已经用Shell指令删除,故输出为操作失败(文件不存在或删除失败)

  • (10)在HDFS中,将文件从源路径移动到目的路径。

    Shell命令

    $ hdfs dfs -mv text.txt text2.txt

    运行结果截图:

  • Java代码
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.*;
    import java.io.*;
    public class HDFSApi {
     /**
     * 移动文件
     */
     public static boolean mv(Configuration conf, String remoteFilePath, String 
    remoteToFilePath) throws IOException {
     FileSystem fs = FileSystem.get(conf);
     Path srcPath = new Path(remoteFilePath);
     Path dstPath = new Path(remoteToFilePath);
     boolean result = fs.rename(srcPath, dstPath);
     fs.close();
     return result;
     }
     
    /**
    * 主函数
    */
    public static void main(String[] args) {
    Configuration conf = new Configuration();
     conf.set("fs.default.name","hdfs://localhost:9000");
    String remoteFilePath = "hdfs:///user/hadoop/text.txt"; // 源文件 HDFS 路径
    String remoteToFilePath = "hdfs:///user/hadoop/new.txt"; // 目的 HDFS 路径
    try {
    if ( HDFSApi.mv(conf, remoteFilePath, remoteToFilePath) ) {
    System.out.println(" 将文件 " + remoteFilePath + " 移动到 " + 
    remoteToFilePath);
    } else {
    System.out.println("操作失败(源文件不存在或移动失败)");
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    运行结果截图:

2. 编程实现一个类MyFSDataInputStream,该类继承org.apache.hadoop.fs.FSDataInputStream,要求如下:

  • (1)实现按行读取HDFS中指定文件的方法readLine():如果读到文件末尾,则返回空,否则返回文件一行的文本。

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.io.*;
public class MyFSDataInputStream extends FSDataInputStream {
public MyFSDataInputStream(InputStream in) {
super(in);
}
/**
 * 实现按行读取
 * 每次读入一个字符,遇到"\n"结束,返回一行内容
 */
public static String readline(BufferedReader br) throws IOException {
char[] data = new char[1024];
int read = -1;
int off = 0; 
// 循环执行时,br 每次会从上一次读取结束的位置继续读取
//因此该函数里,off 每次都从 0 开始
while ( (read = br.read(data, off, 1)) != -1 ) {
if (String.valueOf(data[off]).equals("\n") ) {
off += 1;
break;
}
off += 1;
}
if (off > 0) {
return String.valueOf(data);
} else {
return null;
}
}
/**
 * 读取文件内容
 */
 public static void cat(Configuration conf, String remoteFilePath) throws IOException {
 FileSystem fs = FileSystem.get(conf);
 Path remotePath = new Path(remoteFilePath);
 FSDataInputStream in = fs.open(remotePath);
 BufferedReader br = new BufferedReader(new InputStreamReader(in));
 String line = null;
 while ( (line = MyFSDataInputStream.readline(br)) != null ) {
 System.out.println(line);
 }
 br.close();
 in.close();
 fs.close();
 }
/**
* 主函数
*/
public static void main(String[] args) {
Configuration conf = new Configuration();
 conf.set("fs.default.name","hdfs://localhost:9000");
String remoteFilePath = "/user/hadoop/text.txt"; // HDFS 路径
try {
MyFSDataInputStream.cat(conf, remoteFilePath);
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果截图:

3. 查看Java帮助手册或其它资料,用java.net.URLorg.apache.hadoop.fs.FsURLStreamHandlerFactory编程完成输出HDFS中指定文件的文本到终端中。

import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import java.io.*;
import java.net.URL;
public class HDFSApi {
static{ 
 URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory()); 
 }
​
/**
* 主函数
*/
public static void main(String[] args) throws Exception {
String remoteFilePath = "hdfs:///user/hadoop/text.txt"; // HDFS 文件
InputStream in = null; 
 try{ 
 /* 通过 URL 对象打开数据流,从中读取数据 */
 in = new URL(remoteFilePath).openStream(); 
 IOUtils.copyBytes(in,System.out,4096,false); 
 } finally{ 
 IOUtils.closeStream(in); 
 } 
}
}

运行结果截图:

出现的问题:

问题:

出现如下所示报错:

解决方法:

未启动hadoop,启动hadoop即可。

问题:

Java代码头文件报异常。

解决方法:

将所需的jar包全部导入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值