本節(jié)內(nèi)容
1.項目功能和結(jié)構(gòu)分析
2.定義接口統(tǒng)一回調(diào)接口
3.解析指令&自定義異常
4.cd和cd..指令實現(xiàn)
5.rm和ls指令實現(xiàn)
6.copy指令實現(xiàn)
一、項目功能和結(jié)構(gòu)分析
1.具體功能:首先程序運行起來會提示對應的路徑,①輸入ls就可以查看當前的所有內(nèi)容 ②如果想要進入某一個目錄里面,就輸入cd+目錄名稱 ③創(chuàng)建一個新目錄:輸入mkdir+目錄名稱 ④刪除這個目錄:輸入rf+目錄名稱 ⑤返回桌面:輸入cd..
2.結(jié)構(gòu)分析
①首先有一個CommendTool類用來模擬界面,需要記錄當前目錄,還有一個start()方法,讓這個界面啟動起來。
②然后有一個CommendOperation類來等待用戶輸入,在這里面有一個readCommend()方法來讀取指令,然后解析相應的操作(比如增加目錄,刪除目錄等),之后再把這個結(jié)果回調(diào)給CommendTool
③為了方便前面兩個類的通信,我們可以統(tǒng)一一個接口,在這個接口里面包含一些方法(List:將它列出來, mkdir:創(chuàng)建目錄,copy:拷貝文件或文件夾,remove:刪除,cd_to_child:跳轉(zhuǎn)到子目錄,cd_to_parent:返回到上一級)
④一旦readCommend()將命令解析出來,CommendTool就可以通過接口來實現(xiàn)相應的方法
⑤iCmd接口規(guī)定我們有哪些指令
⑥如果調(diào)用ls方法,將所有的目錄展示出來,那我們就需要一個FileManager類用來管理文件的所有操作,使用單例設計模式
二、定義接口統(tǒng)一回調(diào)接口
1.首先定義一個CommendTool類,在類里面,我們要定義一個目錄,它可以默認啟動起來顯示操作、,還要定義一個變量記錄當前操作的目錄路徑,調(diào)用構(gòu)造方法,讓這個變量指向那個默認路徑
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.創(chuàng)建一個CommendOperation類,接收用戶輸入和解析輸入類型
public class CommendOperation {
接收用戶輸入的指令
public void readCommend(){
}
}
這個時候可以補充start方法,首先定義一個CommendOperation類的對象,然后通過這個對象調(diào)用readCommend方法,以便進行相應的操作
public void start(){
創(chuàng)建讀取指令的對象
CommendOperation operation= new CommendOperation();
System.out.println("歡迎使用計算機鬼才定制版命令行工具");
用戶輸入指令
operation.readCommend();
}
3.在接收了指令之后我們就要解析指令,那么在解析指令之前我們需要一個接口包含所有的指令。因為接口默認屬性都為public static final類型,所以不用特地加上這個public static final。
public interface ICmd {
String LS= "ls"; 列出當前目錄內(nèi)容
String MKDIR="mkdir"; 創(chuàng)建目錄
String COPY="copy"; 拷貝
String RM="rm"; 刪除
String CD="cd"; 進入一個目錄
String CDP="cd.."; 進入上一層目錄
}
4.定義一個ICommend接口,里面包含所有操作對應的抽象方法。
public interface ICommend {
1.列出當前目錄的所有內(nèi)容 名字+size
boolean list();
2.創(chuàng)建一個目錄
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;
}
先添加這些方法,后面再一步步慢慢實現(xiàn)。這個時候我們還要修改一下CommendOperation類。
6.回調(diào)給CommendTool的應該是ICommend類的一個對象,所以要創(chuàng)建一個ICommend的對象,并將其作為readCommend的一個參數(shù)。解析指令最好是另外寫一個函數(shù)包裹起來,使用的時候調(diào)用該方法即可。
public class CommendOperation {
1.回調(diào)對象
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函數(shù)調(diào)用里的參數(shù)
operation.readCommend(this);
2.在ICmd接口里面添加一個指令數(shù)組,里面包含所有正確的指令
String[] COMMONDS=new String[]{LS,MKDIR,COPY,RM,CD,CDP};
3.接著我們逐步實現(xiàn)解析指令的函數(shù),我們可以將指令用空格符分隔開,然后獲取用戶的指令
將指令以空格為分隔符分開
String[] compoents=commond.split(" ");
獲取用戶指令
String cmd= compoents[0];
4.為了判斷指令存不存在,我們需要調(diào)用contains方法,但是這個是List的方法,所以我們要把前面定義的普通數(shù)組轉(zhuǎn)化為List數(shù)組。在 CommendOperation類里面定義數(shù)組,在這個類的構(gòu)造方法里面進行轉(zhuǎn)換
// 保存所有指令
private List<String> commonts;
public CommendOperation(){
mScanner=new Scanner(System.in);
// 將普通的Array類型轉(zhuǎn)換為List
commonts= Arrays.asList(ICmd.COMMONDS);
}
5.如果指令不存在,我們就要拋出相應的異常了,但因為這個異常不是系統(tǒng)自帶的,所以我們要自己定義一個異常。自定義異常里面添加一個內(nèi)部類,然后實現(xiàn)這個內(nèi)部類的構(gòu)造方法
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{...內(nèi)部內(nèi)容見上}
public void parseCommend(String commond) throws
GeniusException.CommondNotExistException{...內(nèi)部內(nèi)容見上}
7.那么在CommendTool 類里面的start()方法里接收用戶的輸入就需要添加一個try-catch方法
//用戶輸入指令
try {
operation.readCommend(this);
} catch (GeniusException.CommondNotExistException e) {
System.out.println(e.getMessage());
}
8.然后我們接著完成解析指令的函數(shù),如果指令不存在就拋出異常
判斷指令是否存在
if(!commonts.contains(cmd)){
1. 輸入指令不存在
2.拋出異常
throw new GeniusException.CommondNotExistException("指令不存在");
}
四、cd和cd..指令實現(xiàn)
1.在start方法里面我們要顯示一下目錄替換,可以另外寫一個showparent方法,在start里面調(diào)用即可。
顯示目錄替換
showParent();
2.想要顯示上一個目錄的名稱,我們可以通過\\ 獲取最后一個字符串的索引值,然后通過substring方法獲取這個內(nèi)容,然后再將它輸出
private void showParent(){
1.獲取最后一個\\的index
int start= currentDirPath.lastIndexOf("\\");
2.獲取最后的內(nèi)容
String parent= currentDirPath.substring(start);
3.輸出提示內(nèi)容
System.out.print(parent+"#");
}
3.因為顯示這個內(nèi)容以及拋出異常是需要不斷重復進行的,所以我們可以用一個while循環(huán)將其包裹起來
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.然后讓前面的函數(shù)都繼承這個異常
public void readCommend(ICommend listener) throws
GeniusException.CommondNotExistException,
CommendTool.GeniusException.CommondArgumentException{...}
public void parseCommend(String commond) throws
GeniusException.CommondNotExistException,
GeniusException.CommondArgumentException {...}
6.接著可以實現(xiàn)switch里的ICmd.CD板塊里的內(nèi)容
switch (cmd){
case ICmd.CD:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 參數(shù)不正確");
}
listener.cd_to_child(compoents[1]);
break;
}
7.然后實現(xiàn)cd_to_child函數(shù)
@Override
public boolean cd_to_child(String path) {
currentDirPath= currentDirPath.append("\\"+path);
return false;
}
8.接著實現(xiàn)switch里的CDP,compoents.length!=1表明輸多了參數(shù),不符合我們只有一個命令的這種可能
case ICmd.CDP:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("cd.. 不需要參數(shù)");
}
listener.cd_to_parent();
break;
9.然后實現(xiàn)cd_to_parent函數(shù),因為是返回上一個目錄,所以我們刪除一部分后綴即可,那么就調(diào)用delete函數(shù),需要輸入刪除的部分的首尾索引值
@Override
public boolean cd_to_parent() {
int start= currentDirPath.toString().lastIndexOf("\\");
int end= currentDirPath.length();
currentDirPath.delete(start,end);
return false;
}
10.然后實現(xiàn)Switch里的MKDIR,因為創(chuàng)建一個目錄,所以需要兩個解析式,前面是選擇的操作,后面是創(chuàng)建的目錄名稱
case ICmd.MKDIR:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 參數(shù)不正確");
}
listener.mkdir(compoents[1]);
break;
11.然后實現(xiàn)CommendTool里的mkdir函數(shù)
@Override
public boolean mkdir(String path) {
//拼接完整路徑
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().mkdir(dirPath);
return false;
}
12.因為要創(chuàng)建新目錄,所以不得不再創(chuàng)建一個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 如果路徑中的目錄不存在,也會自動創(chuàng)建
return file.mkdir();
}
}
五、rm和ls指令實現(xiàn)
1.實現(xiàn)switch里面的RM方法,因為有兩個解析式,一個是操作,還有一個是要刪除的目錄的名字,所以判斷l(xiāng)ength是否=2
case ICmd.RM:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("rm 參數(shù)不正確");
}
listener.remove(compoents[1]);
break;
2.然后實現(xiàn)CommendTool里的remove函數(shù),先拼接路徑再刪除
@Override
public boolean remove(String path) {
String dirPath=currentDirPath.toString()+"\\"+path;
FileManager.getInstance().remove(dirPath);
return false;
}
3.在FileManager類里面添加remove函數(shù),關于文件的操作都需要在FileManager里面添加相應的方法。如果目錄存在才需要刪除,否則就返回false
public boolean remove(String path){
File file =new File(path);
if(file.exists()){
return file.delete();
}
return false;
}
4.實現(xiàn)switch里的LS方法,它也只需要一個解析式即可,不需要參數(shù)
case ICmd.LS:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("ls 不需要參數(shù)");
}
listener.list();
5.然后實現(xiàn)CommendTool里的list方法,如果想要讓顯示的內(nèi)容對齊,就可以添加一個for循環(huán),那個50為空格數(shù)
@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指令實現(xiàn)
1.實現(xiàn)switch里的COPY操作,因為有選擇操作,還有原文件名以及目標文件名,所以length與3比較
case ICmd.COPY:
if(compoents.length!=3){
throw new GeniusException.CommondArgumentException("copy 參數(shù)不正確");
}
listener.copy(compoents[1],compoents[2]);
break;
2.實現(xiàn)CommendTool里的copy函數(shù)
@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 {
//創(chuàng)建當前目錄
desfile.mkdir();
//需要將原目錄的所有內(nèi)容copy到des目錄
for (File file:srcfile.listFiles()){
copy(file.getAbsolutePath(),des+"\\"+file.getName());
}
}
return true;
}
拷貝文件函數(shù)見下,使用字節(jié)數(shù)組會快一點,最后要用flush刷新一下。把創(chuàng)建輸入流的那幾行放進try的括號里面這樣就不需要另外單獨close了
public void copyFile(String src,String des){
try (//創(chuàng)建輸入流
FileInputStream fis= new FileInputStream(src);
BufferedInputStream bis= new BufferedInputStream(fis);
//創(chuàng)建輸出流
FileOutputStream fos =new FileOutputStream(des);
BufferedOutputStream bos= new BufferedOutputStream(fos);){
//創(chuàng)建Buffer
byte[] Buffer=new byte[1024];
int len=0;
while ((len=bis.read())!=-1){
bos.write(Buffer);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
歐克,以上就是我們今天的全部內(nèi)容,再見!
以下為全部的源代碼
public interface ICmd {
String LS= "ls";//列出當前目錄內(nèi)容
String MKDIR="mkdir";//創(chuàng)建目錄
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 {
//列出當前目錄的所有內(nèi)容+ 名字+size
boolean list();
//創(chuàng)建一個目錄
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 {
//回調(diào)對象
private ICommend listener;
//獲取輸入信息
private Scanner mScanner;
//保存所有指令
private List<String> commonts;
public CommendOperation(){
mScanner=new Scanner(System.in);
//將普通的Array類型轉(zhuǎn)換為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 參數(shù)不正確");
}
listener.cd_to_child(compoents[1]);
break;
case ICmd.CDP:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("cd.. 不需要參數(shù)");
}
listener.cd_to_parent();
break;
case ICmd.MKDIR:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("cd 參數(shù)不正確");
}
listener.mkdir(compoents[1]);
break;
case ICmd.RM:
if(compoents.length!=2){
throw new GeniusException.CommondArgumentException("rm 參數(shù)不正確");
}
listener.remove(compoents[1]);
break;
case ICmd.LS:
if(compoents.length!=1){
throw new GeniusException.CommondArgumentException("ls 不需要參數(shù)");
}
listener.list();
case ICmd.COPY:
if(compoents.length!=3){
throw new GeniusException.CommondArgumentException("copy 參數(shù)不正確");
}
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 如果路徑中的目錄不存在,也會自動創(chuàng)建
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 {
//創(chuàng)建當前目錄
desfile.mkdir();
//需要將原目錄的所有內(nèi)容copy到des目錄
for (File file:srcfile.listFiles()){
copy(file.getAbsolutePath(),des+"\\"+file.getName());
}
}
return true;
}
public void copyFile(String src,String des){
try (//創(chuàng)建輸入流
FileInputStream fis= new FileInputStream(src);
BufferedInputStream bis= new BufferedInputStream(fis);
//創(chuàng)建輸出流
FileOutputStream fos =new FileOutputStream(des);
BufferedOutputStream bos= new BufferedOutputStream(fos);){
//創(chuàng)建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() {
//創(chuàng)建讀取指令的對象
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("\\");
//獲取最后的內(nèi)容
String parent= currentDirPath.substring(start);
//輸出提示內(nèi)容
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();
}
}