记录一下大数据实验,利用Hadoop提供的Java API进行编程,实现一个简单的Hshell
Hshell具体功能如下:
1.使用HShell -cp 本地路径 HDFS路径,将文件从Linux本地文件系统拷贝到HDFS指定路径上。
2.使用HShell -rm 路径删除文件
3.使用HShell -rm -r 路径删除目录
4.使用HShell -cp -r 本地目录路径 HDFS路径,将目录从Linux本地拷贝到HDFS指定路径上。
5.使用HShell -list 路径显示某个文件的信息或者某个目录的信息
6.使用HShell -mv 路径 路径移动文件或者重命名文件
7.使用HShell -find 文件名 目录实现在目录下递归查找某个文件名的文件。
实验整体没什么难度,会Java的基本语法就能完成,稍微有难度的地方是第4个功能,需要递归拷贝目录,其他的只要调用API就行。
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.util.Scanner;
import java.net.URI;
import java.io.File;
public class Hshell {
public static void main(String[] args) {
while(true){
try {
Scanner input=new Scanner(System.in);
String command[]=input.nextLine().split("\\s+");
if(command[0].equals("Hshell")){
switch (command[1]){
case "-cp":
if(command[2].equals("-r")){
copyLocalDir(command[3],command[4]);
}
else{
copyLocalFile(command[2], command[3]);
}
break;
case "-rm":
if(command[2].equals("-r")){
deletedir(command[3]);
}
else{
deleteFile(command[2]);
}
break;
case "-list":
disinfo(command[2]);
break;
case "-find":
findfile(command[2],command[3]);
break;
default:
System.out.println("Command Syntax Error!");
}
}
else if(command[0].equals("q")) {System.exit(0);}
else{System.out.println("Command Syntax Error!");}
}catch(Exception e) {
e.printStackTrace();
}
}
}
public static boolean copyLocalFile(String lPath,String hPath){
try{
FileSystem hdfs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
Path localPath = new Path(lPath);
File localFile=new File(lPath);
Path hdfsPath = new Path(hPath);
if(localFile.exists())
{
// hdfs.mkdirs(hdfsPath);可以不用
hdfs.copyFromLocalFile(true,localPath,hdfsPath);
System.out.println("Copy successfully!");
}
else{
System.out.println("Local file is not exist!");
hdfs.close();
return false;
}
hdfs.close();
}catch(Exception e){
e.printStackTrace();
}
return true;
}
public static boolean deleteFile(String deletepath){
try{
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
if(fs.exists(new Path(deletepath))) {
if(fs.delete(new Path(deletepath),false)){
System.out.println("File "+ deletepath +" has been deleted successfully!");
}
} else {
System.out.println("File not Exists!");
fs.close();
return false;
}
fs.close();
}catch (Exception e){
e.printStackTrace();
}
return true;
}
public static boolean deletedir(String deleteDir){
try {
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
if(fs.delete(new Path(deleteDir),true)){
System.out.println("Directory "+ deleteDir +" has been deleted successfully!");
}
fs.close();
}catch(Exception e) {
e.printStackTrace();
}
return true;
}
public static boolean copyLocalDir(String srcDir,String destDir){
try{
File f=new File(srcDir);
FileSystem hdfs=FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
if(f.exists()){
if(f.isDirectory())
{
String newdir=destDir.endsWith("/")?destDir+f.getName():destDir+"/"+f.getName();//新的路径
hdfs.mkdirs(new Path(newdir));
File[] files=f.listFiles();
for(File file:files)
{
if(file.isDirectory()){
copyLocalDir(file.getAbsolutePath(),newdir);
}else{
hdfs.copyFromLocalFile(new Path(file.getAbsolutePath()),new Path(newdir));
}
}
}
else{
System.out.println(srcDir+"is not a directory!");
hdfs.close();
return false;
}
}
else{
System.out.println("Directory is not exsists!");
hdfs.close();
return false;
}
hdfs.close();
}catch(Exception e){e.printStackTrace();}
return true;
}
public static boolean disinfo(String srcpath)
{
try {
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
Path dirpath=new Path(srcpath);
if(fs.getFileStatus(dirpath).isFile()){
System.out.println(fs.getFileStatus(dirpath));
}
else if(fs.getFileStatus(dirpath).isDirectory())
{
FileStatus[] stats = fs.listStatus(dirpath);
Path[] paths = FileUtil.stat2Paths(stats);
for(Path p : paths)
if(fs.getFileStatus(p).isFile()) {
System.out.println(fs.getFileStatus(p));
}
else System.out.println(p.getName());
}
else{
System.out.println("Error path!");
fs.close();
return false;
}
fs.close();
}catch(Exception e) {
e.printStackTrace();
}
return true;
}
public static boolean mvfile(String srcpath,String destpath)
{
try {
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
if(fs.exists(new Path(srcpath))) {
fs.rename(new Path(srcpath),new Path(destpath));
} else {
System.out.println("File not Exists!");
fs.close();
return false;
}
}catch(Exception e) {
e.printStackTrace();
}
return true;
}
public static boolean findfile(String filename,String dirpath){
try{
FileSystem hdfs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());
Path dpath=new Path(dirpath);
if(hdfs.exists(dpath))
{
if(hdfs.getFileStatus(dpath).isDirectory()){
FileStatus[] stats = hdfs.listStatus(dpath);
for(FileStatus st:stats){
if(st.isFile()){
if(st.getPath().getName().equals(filename)){
System.out.println(st.getPath().toString());
hdfs.close();
return true;
}
}
else{
findfile(filename,st.getPath().toString());
}
}
hdfs.close();
return false;
}
else{
System.out.println(dirpath+" is not a directory!");
}
}
else{
System.out.println("Directory is not exist!");
hdfs.close();
return false;
}
hdfs.close();
}catch(Exception e){
e.printStackTrace();
}
return true;
}
}
创建目录 public boolean mkdirs(Path f) throws IOException
目录存在性 public boolean exists(Path f) throws IOException
列出目录中的内容 public abstract FileStatus[] listStatus(Path f) throws FileNotFoundException, IOException
删除目录 public abstract boolean delete(Path f,boolean recursive) throws IOException
** recursive,是否需要递归删除。如果是删除目录的话,将该参数设置为true。否则,设置为false.**
创建文件 public FSDataOutputStream create(Path f) throws IOException
根据参数的不同,create函数有多种重载类型
文件存在性判断 public boolean exists(Path f) throws IOException
文件写
** HDFS不支持文件的随机写,写文件的方式有两种:1)文件不存在,创建文件之后,开始对文件的内容进行写入。2)文件存在,打开文件,在文件尾部追加写。**
对于第一种方式,由于调用create方法后会返回FSDataOutputStream对象,使用该对象对文件进行写操作。第二种方式,使用FileSystem类的append接口,该接口也会返回FSDataOutputStream对象,同样使用该对象可对文件进行追加操作。
FSDataOutputStream有三个常用的方法,分别为write,flush,close函数。write将数据写入到文件中,flush将数据缓存在内存中的数据更新到磁盘,close则关闭流对象。
主函数示例
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());
Path srcPath = new Path(filePath);
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();
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();
}
}
读文件
public FSDataInputStream open(Path f) throws IOException
public abstract FSDataInputStream open(Path f,int bufferSize) throws IOException
其中,bufferSize的含义为读取过程中所使用的缓冲区的大小。
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());
Path srcPath = new Path(filePath);
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
文件删除
public abstract boolean delete(Path f,boolean recursive) throws IOException
recursive,是否需要递归删除。如果是删除目录的话,将该参数设置为true。否则,设置为false.
利用Scanner
Scanner简介:
(1)Scanner是一个扫描器,对于键盘输入或者文件中的数据,先存到缓存区等待读取,它判断读取结束的标示是:空格,回车,tab 等;
(2)next()
和nextInt()
方法读取到任意间隔符(如空格和回车)就结束,nextLine()
读取到回车结束也就是“\r”,next()
返回值为String类型,nextLine()
返回值为String
类型,nextInt()
返回值为Int类型。
使用:
1) 利用next()
方法时,不会以回车作为结束,可能导致用户的命令分为多行输入。例如Hshell+换行±rm+换行+路径文件。
2) 利用nextline读取命令行,以回车作为结束符。
利用String类的split()
String的split方法支持正则表达式,正则表达式\s表示匹配任何空白字符,+表示匹配一次或多次。
File filename=new File(路径);
Filename.exists();判断该路径是否存在,存在返回true
filename.isDirectory():判断是否为目录,目录返回true
isfile() 判断是否为文件,文件返回true