本节内容
1.项目功能和结构分析
2.定义接口统一回调接口
3.解析指令&自定义异常
4.cd和cd..指令实现
5.rm和ls指令实现
6.copy指令实现
一、项目功能和结构分析
1.具体功能:首先程序运行起来会提示对应的路径,①输入ls就可以查看当前的所有内容 ②如果想要进入某一个目录里面,就输入cd+目录名称 ③创建一个新目录:输入mkdir+目录名称 ④删除这个目录:输入rf+目录名称 ⑤返回桌面:输入cd..
2.结构分析
①首先有一个CommendTool类用来模拟界面,需要记录当前目录,还有一个start()方法,让这个界面启动起来。
②然后有一个CommendOperation类来等待用户输入,在这里面有一个readCommend()方法来读取指令,然后解析相应的操作(比如增加目录,删除目录等),之后再把这个结果回调给CommendTool
③为了方便前面两个类的通信,我们可以统一一个接口,在这个接口里面包含一些方法(List:将它列出来, mkdir:创建目录,copy:拷贝文件或文件夹,remove:删除,cd_to_child:跳转到子目录,cd_to_parent:返回到上一级)
④一旦readCommend()将命令解析出来,CommendTool就可以通过接口来实现相应的方法
⑤iCmd接口规定我们有哪些指令
⑥如果调用ls方法,将所有的目录展示出来,那我们就需要一个FileManager类用来管理文件的所有操作,使用单例设计模式
二、定义接口统一回调接口
1.首先定义一个CommendTool类,在类里面,我们要定义一个目录,它可以默认启动起来显示操作、,还要定义一个变量记录当前操作的目录路径,调用构造方法,让这个变量指向那个默认路径
public class CommendTool {
默认启动起来显示操作的目录
private static final String DESK_TOP="C:\\Users\\86178\\Desktop";
记录当前操作的目录路径
private StringBuilder currentDirPath;
public CommendTool() {
currentDirPath=DESK_TOP;
}
启动命令行工具
public void start(){
System.out.println("欢迎使用计算机鬼才定制版命令行工具");
}
}
2.创建一个CommendOperation类,接收用户输入和解析输入类型
public class CommendOperation {
接收用户输入的指令
public void readCommend(){
}
}
这个时候可以补充start方法,首先定义一个CommendOperation类的对象,然后通过这个对象调用readCommend方法,以便进行相应的操作
public void start(){
创建读取指令的对象
CommendOperation operation= new CommendOperation();
System.out.println("欢迎使用计算机鬼才定制版命令行工具");
用户输入指令
operation.readCommend();
}
3.在接收了指令之后我们就要解析指令,那么在解析指令之前我们需要一个接口包含所有的指令。因为接口默认属性都为public static final类型,所以不用特地加上这个public static final。
public interface ICmd {
String LS= "ls"; 列出当前目录内容
String MKDIR="mkdir"; 创建目录
String COPY="copy"; 拷贝
String RM="rm"; 删除
String CD="cd"; 进入一个目录
String CDP="cd.."; 进入上一层目录
}
4.定义一个ICommend接口,里面包含所有操作对应的抽象方法。
public interface ICommend {
1.列出当前目录的所有内容 名字+size
boolean list();
2.创建一个目录
boolean mkdir(String path);
3.将src的文件复制到des的位置
boolean copy(String src,String des);
4.删除文件/目录
boolean remove(String path);
5.切换当前目录到子目录
boolean cd_to_child(String path);
6.切换到上一层目录
boolean cd_to_parent();
}
5.然后让CommendTool类继承ICommend接口,并添加相应的抽象方法。
@Override
public boolean list() {
return false;
}
@Override
public boolean mkdir(String path) {
return false;
}
@Override
public boolean copy(String src, String des) {
return false;
}
@Override
public boolean remove(String path) {
return false;
}
@Override
public boolean cd_to_child(String path) {
return false;
}
@Override
public boolean cd_to_parent() {
return false;
}
先添加这些方法,后面再一步步慢慢实现。这个时候我们还要修改一下CommendOperation类。
6.回调给CommendTool的应该是ICommend类的一个对象,所以要创建一个ICommend的对象,并将其作为readCommend的一个参数。解析指令最好是另外写一个函数包裹起来,使用的时候调用该方法即可。
public class CommendOperation {
1.回调对象
private ICommend listener;
2.获取输入信息
private Scanner mScanner;
public CommendOperation(){
mScanner=new Scanner(System.in);
}
3.接收用户输入的指令
public void readCommend(ICommend listener){
this.listener=listener;
4. 接收指令
String commend=mScanner.nextLine();
5. 解析指令
parseCommend(commend);
}
public void parseCommend(String cmd){
}
}
三、解析指令&自定义异常
1.先补充一下readcommend函数调用里的参数
operation.readCommend(this);
2.在ICmd接口里面添加一个指令数组,里面包含所有正确的指令
String[] COMMONDS=new String[]{LS,MKDIR,COPY,RM,CD,CDP};
3.接着我们逐步实现解析指令的函数,我们可以将指令用空格符分隔开,然后获取用户的指令
将指令以空格为分隔符分开
String[] compoents=commond.split(" ");
获取用户指令
String cmd= compoents[0];
4.为了判断指令存不存在,我们需要调用contains方法,但是这个是List的方法,所以我们要把前面定义的普通数组转化为List数组。在 CommendOperation类里面定义数组,在这个类的构造方法里面进行转换
// 保存所有指令
private List<String> commonts;
public CommendOperation(){
mScanner=new Scanner(System.in);
// 将普通的Array类型转换为List
commonts= Arrays.asList(ICmd.COMMONDS);
}
5.如果指令不存在,我们就要抛出相应的异常了,但因为这个异常不是系统自带的,所以我们要自己定义一个异常。自定义异常里面添加一个内部类,然后实现这个内部类的构造方法
public class GeniusException {
//指令不存在
static class CommondNotExistException extends Exception{
public CommondNotExistException(String s) {
super(s);
}
}
}
6.因为会抛出异常,所以前面的parseCommend()方法和readCommend()方法都需要继承这个异常
public void readCommend(ICommend listener) throws
GeniusException.CommondNotExistException{...内部内容见上}
public void parseCommend(String commond) throws
GeniusException.CommondNotExistException{...内部内容见上}
7.那么在CommendTool 类里面的start()方法里接收用户的输入就需要添加一个try-catch方法
//用户输入指令
try {
operation.readCommend(this);
} catch (GeniusException.CommondNotExistException e) {
System.out.println(e.getMessage());
}
8.然后我们接着完成解析指令的函数,如果指令不存在就抛出异常
判断指令是否存在
if(!commonts.contains(cmd)){
1. 输入指令不存在
2.抛出异常
throw new GeniusException.CommondNotExistException("指令不存在");
}
四、cd和cd..指令实现
1.在start方法里面我们要显示一下目录替换,可以另外写一个showparent方法,在start里面调用即可。
显示目录替换
showParent();
2.想要显示上一个目录的名称,我们可以通过\\ 获取最后一个字符串的索引值,然后通过substring方法获取这个内容,然后再将它输出
private void showParent(){
1.获取最后一个\\的index
int start= currentDirPath.lastIndexOf("\\");
2.获取最后的内容
String parent= currentDirPath.substring(start);
3.输出提示内容
System.out.print(parent+"#");
}
3.因为显示这个内容以及抛出异常是需要不断重复进行的,所以我们可以用一个while循环将其包裹起来
while (true) {
//显示目录替换
showParent();
//用户输入指令
try {
operation.readCommend(this);
} catch (GeniusException.CommondNotExistException e) {
System.out.println(e.getMessage());
}
}
}
4.然后我们可以开始解析指令,用switch语句来完成各个部分的功能。首先是ICmd.CD,然后判断它的compoents.length!=2(这个就是解析的语句不等于2,也就是要么没有要进入的目录,要么有多个目录,都不符合我们的要求),那么就抛出异常。所以我们还要自己另外定义一个异常
static class CommondArgumentException extends Exception{
public CommondArgumentException(String s) {
super(s);
}
}
5.然后让前面的函数都继承这个异常
public void readCommend(ICommend listener) throws
GeniusException.CommondNotExistException,
CommendTool.GeniusException.CommondArgumentException{...}
public void parseCommend(String commond) throws
GeniusException.CommondNotExistException,
GeniusException.CommondArgumentException {...}
6.接着可以实现switch里的ICmd.CD板块里的内容
switch (cmd){
case ICmd.CD:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 参数不正确");
}
listener.cd_to_child(compoents[1]);
break;
}
7.然后实现cd_to_child函数
@Override
public boolean cd_to_child(String path) {
currentDirPath= currentDirPath.append("\\"+path);
return false;
}
8.接着实现switch里的CDP,compoents.length!=1表明输多了参数,不符合我们只有一个命令的这种可能
case ICmd.CDP:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("cd.. 不需要参数");
}
listener.cd_to_parent();
break;
9.然后实现cd_to_parent函数,因为是返回上一个目录,所以我们删除一部分后缀即可,那么就调用delete函数,需要输入删除的部分的首尾索引值
@Override
public boolean cd_to_parent() {
int start= currentDirPath.toString().lastIndexOf("\\");
int end= currentDirPath.length();
currentDirPath.delete(start,end);
return false;
}
10.然后实现Switch里的MKDIR,因为创建一个目录,所以需要两个解析式,前面是选择的操作,后面是创建的目录名称
case ICmd.MKDIR:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 参数不正确");
}
listener.mkdir(compoents[1]);
break;
11.然后实现CommendTool里的mkdir函数
@Override
public boolean mkdir(String path) {
//拼接完整路径
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().mkdir(dirPath);
return false;
}
12.因为要创建新目录,所以不得不再创建一个FileManager类,然后采用单例设计模式
public class FileManager {
private static FileManager manager;
private FileManager(){}
public static FileManager getInstance(){
if(manager==null){
synchronized (FileManager.class){
if(manager==null){
manager =new FileManager();
}
}
}
return manager;
}
public boolean mkdir(String path){
File file =new File(path);
if(file.exists()){
return false;
}
//mkdir要求路径中的目录都存在
//mkdirs 如果路径中的目录不存在,也会自动创建
return file.mkdir();
}
}
五、rm和ls指令实现
1.实现switch里面的RM方法,因为有两个解析式,一个是操作,还有一个是要删除的目录的名字,所以判断length是否=2
case ICmd.RM:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("rm 参数不正确");
}
listener.remove(compoents[1]);
break;
2.然后实现CommendTool里的remove函数,先拼接路径再删除
@Override
public boolean remove(String path) {
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().remove(dirPath);
return false;
}
3.在FileManager类里面添加remove函数,关于文件的操作都需要在FileManager里面添加相应的方法。如果目录存在才需要删除,否则就返回false
public boolean remove(String path){
File file =new File(path);
if(file.exists()){
return file.delete();
}
return false;
}
4.实现switch里的LS方法,它也只需要一个解析式即可,不需要参数
case ICmd.LS:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("ls 不需要参数");
}
listener.list();
5.然后实现CommendTool里的list方法,如果想要让显示的内容对齐,就可以添加一个for循环,那个50为空格数
@Override
public boolean list() {
File[] files= FileManager.getInstance().list(currentDirPath.toString());
for(File file:files){
//获取文件名
String name= file.getName();
//获取文件长度
long size= file.length();
long kb= size/1024;
long by=size%1024;
System.out.print(name);
for(int i=0;i<50-name.length();i++){
System.out.print(" ");
}
System.out.println(name+" "+kb+"."+by+"kb");
}
return false;
}
6.因为需要展示所有文件目录,所以需要在FilManager添加这个list方法
public File[] list(String path){
File file =new File(path);
if(!file.exists()){
return null;
}
return file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File file, String s) {
if(s.startsWith(".")) {
return false;
}
return true;
}
});
}
因为我们不想展示以“.”开头的隐藏文件,所以我们获取文件的时候需要过滤一下,所以要new 一个FilenameFilter
六、copy指令实现
1.实现switch里的COPY操作,因为有选择操作,还有原文件名以及目标文件名,所以length与3比较
case ICmd.COPY:
if(compoents.length!=3){
throw new GeniusException.CommondArgumentException("copy 参数不正确");
}
listener.copy(compoents[1],compoents[2]);
break;
2.实现CommendTool里的copy函数
@Override
public boolean copy(String src, String des) {
String srcPath=currentDirPath.toString()+"\\"+src;
String desPath=currentDirPath.toString()+"\\"+des;
FileManager.getInstance().copy(srcPath,desPath);
return false;
}
3.因为涉及到文件的拷贝,那么就需要在FileManager里面添加这个copy方法
public boolean copy(String src,String des){
File srcfile= new File(src);
File desfile= new File(des);
//判断文件是否存在
if(!srcfile.exists()||!desfile.exists()){
return false;
}
//判断是不是文件
if(srcfile.isFile()){
//直接拷贝文件
copyFile(src,des);
}else {
//创建当前目录
desfile.mkdir();
//需要将原目录的所有内容copy到des目录
for (File file:srcfile.listFiles()){
copy(file.getAbsolutePath(),des+"\\"+file.getName());
}
}
return true;
}
拷贝文件函数见下,使用字节数组会快一点,最后要用flush刷新一下。把创建输入流的那几行放进try的括号里面这样就不需要另外单独close了
public void copyFile(String src,String des){
try (//创建输入流
FileInputStream fis= new FileInputStream(src);
BufferedInputStream bis= new BufferedInputStream(fis);
//创建输出流
FileOutputStream fos =new FileOutputStream(des);
BufferedOutputStream bos= new BufferedOutputStream(fos);){
//创建Buffer
byte[] Buffer=new byte[1024];
int len=0;
while ((len=bis.read())!=-1){
bos.write(Buffer);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
欧克,以上就是我们今天的全部内容,再见!
以下为全部的源代码
public interface ICmd {
String LS= "ls";//列出当前目录内容
String MKDIR="mkdir";//创建目录
String COPY="copy";//拷贝
String RM="rm";//删除
String CD="cd";//进入一个目录
String CDP="cd..";//进入上一层目录
String[] COMMONDS=new String[]{LS,MKDIR,COPY,RM,CD,CDP};
}
public interface ICommend {
//列出当前目录的所有内容+ 名字+size
boolean list();
//创建一个目录
boolean mkdir(String path);
//将src的文件复制到des的位置
boolean copy(String src,String des);
//删除文件/目录
boolean remove(String path);
//切换当前目录到子目录
boolean cd_to_child(String path);
//切换到上一层目录
boolean cd_to_parent();
}
public class GeniusException {
//指令不存在
static class CommondNotExistException extends Exception{
public CommondNotExistException(String s) {
super(s);
}
}
static class CommondArgumentException extends Exception{
public CommondArgumentException(String s) {
super(s);
}
}
}
public class CommendOperation {
//回调对象
private ICommend listener;
//获取输入信息
private Scanner mScanner;
//保存所有指令
private List<String> commonts;
public CommendOperation(){
mScanner=new Scanner(System.in);
//将普通的Array类型转换为List
commonts= Arrays.asList(ICmd.COMMONDS);
}
//接收用户输入的指令
public void readCommend(ICommend listener) throws
GeniusException.CommondNotExistException,CommendTool.GeniusException.CommondArgumentException {
this.listener=listener;
//接收指令
String commond=mScanner.nextLine();
// 解析指令
parseCommend(commond);
}
public void parseCommend(String commond) throws
GeniusException.CommondNotExistException,GeniusException.CommondArgumentException {
//将指令以空格为分隔符分开
String[] compoents=commond.split(" ");
//获取用户指令
String cmd= compoents[0];
//判断指令是否存在
if(!commonts.contains(cmd)){
//输入指令不存在
//抛出异常
throw new GeniusException.CommondNotExistException("指令不存在");
}
//存在就解析是哪种指令
switch (cmd){
case ICmd.CD:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 参数不正确");
}
listener.cd_to_child(compoents[1]);
break;
case ICmd.CDP:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("cd.. 不需要参数");
}
listener.cd_to_parent();
break;
case ICmd.MKDIR:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 参数不正确");
}
listener.mkdir(compoents[1]);
break;
case ICmd.RM:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("rm 参数不正确");
}
listener.remove(compoents[1]);
break;
case ICmd.LS:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("ls 不需要参数");
}
listener.list();
case ICmd.COPY:
if(compoents.length!=3){
throw new GeniusException.CommondArgumentException("copy 参数不正确");
}
listener.copy(compoents[1],compoents[2]);
break;
}
}
}
public class FileManager {
private static FileManager manager;
private FileManager(){}
public static FileManager getInstance(){
if(manager==null){
synchronized (FileManager.class){
if(manager==null){
manager =new FileManager();
}
}
}
return manager;
}
public boolean mkdir(String path){
File file =new File(path);
if(file.exists()){
return false;
}
//mkdir要求路径中的目录都存在
//mkdirs 如果路径中的目录不存在,也会自动创建
return file.mkdir();
}
public boolean remove(String path){
File file =new File(path);
if(file.exists()){
return file.delete();
}
return false;
}
public File[] list(String path){
File file =new File(path);
if(!file.exists()){
return null;
}
return file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File file, String s) {
if(s.startsWith(".")) {
return false;
}
return true;
}
});
}
public boolean copy(String src,String des){
File srcfile= new File(src);
File desfile= new File(des);
//判断文件是否存在
if(!srcfile.exists()||!desfile.exists()){
return false;
}
//判断是不是文件
if(srcfile.isFile()){
//直接拷贝文件
copyFile(src,des);
}else {
//创建当前目录
desfile.mkdir();
//需要将原目录的所有内容copy到des目录
for (File file:srcfile.listFiles()){
copy(file.getAbsolutePath(),des+"\\"+file.getName());
}
}
return true;
}
public void copyFile(String src,String des){
try (//创建输入流
FileInputStream fis= new FileInputStream(src);
BufferedInputStream bis= new BufferedInputStream(fis);
//创建输出流
FileOutputStream fos =new FileOutputStream(des);
BufferedOutputStream bos= new BufferedOutputStream(fos);){
//创建Buffer
byte[] Buffer=new byte[1024];
int len=0;
while ((len=bis.read())!=-1){
bos.write(Buffer);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class CommendTool implements ICommend{
//默认启动起来显示操作的目录
private static final String DESK_TOP="C:\\Users\\86178\\Desktop";
//记录当前操作的目录路径
private StringBuilder currentDirPath;
public CommendTool() {
currentDirPath=new StringBuilder(DESK_TOP);
}
//启动命令行工具
public void start() {
//创建读取指令的对象
CommendOperation operation = new CommendOperation();
System.out.println("欢迎使用计算机鬼才定制版命令行工具");
while (true) {
//显示目录替换
showParent();
//用户输入指令
try {
operation.readCommend(this);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
private void showParent(){
//获取最后一个\\的index
int start= currentDirPath.lastIndexOf("\\");
//获取最后的内容
String parent= currentDirPath.substring(start);
//输出提示内容
System.out.print(parent+"#");
}
@Override
public boolean list() {
File[] files= FileManager.getInstance().list(currentDirPath.toString());
for(File file:files){
//获取文件名
String name= file.getName();
//获取文件长度
long size= file.length();
long kb= size/1024;
long by=size%1024;
System.out.print(name);
for(int i=0;i<50-name.length();i++){
System.out.print(" ");
}
System.out.println(name+" "+kb+"."+by+"kb");
}
return false;
}
@Override
public boolean mkdir(String path) {
//拼接完整路径
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().mkdir(dirPath);
return false;
}
@Override
public boolean copy(String src, String des) {
String srcPath=currentDirPath.toString()+"\\"+src;
String desPath=currentDirPath.toString()+"\\"+des;
FileManager.getInstance().copy(srcPath,desPath);
return false;
}
@Override
public boolean remove(String path) {
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().remove(dirPath);
return false;
}
@Override
public boolean cd_to_child(String path) {
currentDirPath= currentDirPath.append("\\"+path);
return false;
}
@Override
public boolean cd_to_parent() {
int start= currentDirPath.toString().lastIndexOf("\\");
int end= currentDirPath.length();
currentDirPath.delete(start,end);
return false;
}
}
public class MyClass {
public static void main(String[] args) {
CommendTool tool=new CommendTool();
tool.start();
}
}
网友评论