這里是該項目作業的要求:
https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2152 ---陳汶濱老師
項目已經上傳github:
https://github.com/DngLing/CountWord
個人PSP表:
PSP2.1 |
PSP階段 |
預估耗時 (分鍾) |
實際耗時 (分鍾) |
Planning |
計划 |
30 |
40 |
· Estimate |
· 估計這個任務需要多少時間 |
|
|
Development |
開發 |
|
|
· Analysis |
· 需求分析 (包括學習新技術) |
30 |
60 |
· Design Spec |
· 生成設計文檔 |
10 |
10 |
· Design Review |
· 設計復審 (和同事審核設計文檔) |
5 |
5 |
· Coding Standard |
· 代碼規范 (為目前的開發制定合適的規范) |
10 |
5 |
· Design |
· 具體設計 |
20 |
20 |
· Coding |
· 具體編碼 |
400 |
250 |
· Code Review |
· 代碼復審 |
15 |
30 |
· Test |
· 測試(自我測試,修改代碼,提交修改) |
20 |
60 |
Reporting |
報告 |
30 |
90 |
· Test Report |
· 測試報告 |
15 |
30 |
· Size Measurement |
· 計算工作量 |
5 |
10 |
· Postmortem & Process Improvement Plan |
· 事后總結, 並提出過程改進計划 |
15 |
20 |
|
合計 |
385 |
780 |
一、語言選擇
我選擇了java來完成我的項目作業,我選擇的理由是:
1.最近真正學習java的常用的類以及IO流;
2.項目中很多功能的實現都可以使用java中一些已有的類(例如在解析大段文字時,Stirng類提供了很多實用方法);
3.我沒有打算做界面系統,不然我還是傾向於學過的C#
二、需求分析與可行性
需求分析
1.通過文件地址獲得該文件的內容(這個文件是一個文本文件,保存着代碼);
2.得到目標文件中的字符數、單詞數、行數、代碼行、空行、注釋行。且對這六種中一些數據做了解釋:
1)字符:所有的空格也算字符;
2)單詞:由空格或逗號隔開的單詞,並且不做有效性判斷;
3)代碼行:非空行注釋行;
4)注釋行 以“ // ”,“ /* ”,“ * ”開頭的行,或者以“ */ ”,“ // ”結尾的行,如果一行代碼后跟了注釋,那么改行也算代碼行。
5)空行:改行沒有代碼,全部是空格或者控制符,如果有,不能超過一個可顯示字符,例如“ { ”。
3.將2中的得到的信息寫出到一個新的文本文件,且 該文件與傳入的文件在同一文件夾下;
4.非圖形界面需要輸入一些指令來執行操作
可行性分析
1.通過IO流可以輕松實現文件的讀寫
三、具體設計與編碼
這是我在ProcessON上制作的類設計圖
下面將給出這些類的設計理念和一些核心代碼
IO_uitl
這個類實現了IO流的輸入與輸出,他有兩個方法,ReadLine()和WriteLine(),下面是ReadLine()方法
public ArrayList<String> ReadLine(String srcPath) throws IOException{ ArrayList<String> strs = new ArrayList<String>(); File srcFile = new File(srcPath); BufferedReader bReader = null; try { bReader = new BufferedReader(new FileReader(srcFile)); String line; while(null!=(line =bReader.readLine())){ strs.add(line); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally{ bReader.close(); } return strs; }
Parser該類將對字串進行解析,得到所需要的結果
下面是部分代碼:
public int getCommtLineNum(ArrayList<String> str){ int num =0; for(int i=0;i<str.size();i++){ String temp = str.get(i).trim(); if(temp.startsWith("//")||temp.startsWith("/*")||temp.startsWith("*")||temp.endsWith("*/")){ num++; } } return num; } public boolean isCommtLine(String str){ boolean flag =false; String temp = str.trim(); if(temp.startsWith("//")||temp.startsWith("/*")||temp.startsWith("*")||temp.endsWith("*/")||temp.startsWith("}//")){ flag = true; } return flag; } public boolean isEmptyLine(String str){ boolean flag = false; if(this.getWordsNum(str)==0&&!this.isCommtLine(str)){ flag = true; } return flag; }
FileInfo 是一個JavaBean,用於傳遞一個文件的信息。
代碼略
Count(統計)類,它擁有一個IO_util和一個Parser的實例對象,並維持了一個FileInfo的實例對象的引用。
通過構造函數聲明這個實例並通過getFileInfo方法將所有所有需要的數據注入到實例的字段中。下面是代碼:
package com.dyf.test; /** * 該方法擁有 * 一個IO_util類的對象 * 一個Parser類的對象 * 該方法維持了一個FileInfo對象的引用 */ import java.io.IOException; import java.util.ArrayList; public class Count { private IO_util iou = null; private Parser par= null; private FileInfo info = null; public Count(FileInfo info){ this.info = info; par = new Parser(); iou = new IO_util(); } /** * 該方法依賴IO_util對象和Parser對象的方法 * 該方法將給引用的FileInfo對象的字段注入數據 * @param srcPath 文件的絕對地址 * @throws IOException */ public void getFileInfo(String srcPath) throws IOException{ ArrayList<String> list = null; list = iou.ReadLine(srcPath); info.setLinesNum(list.size()); for(int i = 0;i<list.size();i++){ info.setWordsNum(info.getWordsNum()+par.getWordsNum(list.get(i))); info.setCharsNum(info.getCharsNum()+par.getCharsNum(list.get(i))); if(par.isEmptyLine(list.get(i))){ info.setEmptyLine(info.getEmptyLine()+1); }else if(par.isCommtLine(list.get(i))){ info.setCommtLine(info.getCommtLine()+1); }else{ info.setCodeLine(info.getCodeLine()+1); } } } }
File_util提供一個通過遍歷得到目標文件夾下的所有子文件夾和文件的路徑並返回
下面是代碼:
package com.dyf.test; /** * 該類用於對文件進行操作 * 該類維持了一個ArrayList<String> 的使用,它將保存一個文件夾路徑下的所有子文件夾和文件的路徑 */ import java.io.File; import java.util.ArrayList; public class File_util { private ArrayList<String> paths; public File_util(ArrayList<String> paths){ this.paths = paths; } /** * 該方法 遞歸的遍歷srcFile路徑下所有的文件和子文件夾的地址 * @param srcFile */ public void getPath(File srcFile){ if(null == srcFile||!srcFile.exists()){ return; } paths.add(srcFile.getAbsolutePath()); if(srcFile.isDirectory()){ for(File file:srcFile.listFiles()) getPath(file); } } }
TestClient 客戶端 代碼如下
package com.dyf.test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Scanner; public class TestClient { public static void main(String[] args) throws IOException { boolean switchflag = true; while(switchflag){ System.out.println("-----COUNTWORD-----"); System.out.println("-------------------"); System.out.println("輸入 -c 獲得當前文件字符數"); System.out.println("輸入 -w 獲得當前文件單詞數"); System.out.println("輸入 -l 獲得當前文件行數"); System.out.println("輸入 -e 獲得當前文件所有信息(上述信息加上代碼行、注釋行和空行)"); System.out.println("輸入 -s 遍歷當前文件夾下所有文件的信息"); System.out.println("輸入 -x:end結束程序"); System.out.println("輸入實例 -e E:/www/exple.java"); System.out.println("-------------------"); System.out.println("請輸入操作符:\n"); Scanner sc = new Scanner(System.in); String str = sc.nextLine(); int pointins = str.indexOf("-"); int pointpath = str.indexOf(":"); String ins = null; String path = null; try{ ins =str.substring(pointins, pointins+2); path = str.substring(pointpath-1).trim(); }catch(StringIndexOutOfBoundsException e){ System.out.println("你的輸入有問題,請檢查並重新輸入:\n"); continue; } switch(ins){ case "-e": FileInfo info = new FileInfo(); Count cou = new Count(info); cou.getFileInfo(path); System.out.println("-----------"); System.out.println(info); break; case "-s": ArrayList<String> paths = new ArrayList<String>(); File_util fu = new File_util(paths); fu.getPath(new File(path)); for(int i=0;i<paths.size();i++){ String line = paths.get(i); if(line.endsWith(".txt")){ FileInfo info1 = new FileInfo(); Count cou1 = new Count(info1); cou1.getFileInfo(line); System.out.println("---------"); System.out.println(line); System.out.println(info1); System.out.println("\n"); } } break; case "-c": FileInfo info2 = new FileInfo(); Count cou2 = new Count(info2); cou2.getFileInfo(path); System.out.println("CharNum:"+info2.getCharsNum()); System.out.println("\n"); break; case "-w": FileInfo info3 = new FileInfo(); Count cou3 = new Count(info3); cou3.getFileInfo(path); System.out.println("WordsNum:"+info3.getWordsNum()); System.out.println("\n"); break; case "-l": FileInfo info4 = new FileInfo(); Count cou4 = new Count(info4); cou4.getFileInfo(path); System.out.println("LinesNum:"+info4.getLinesNum()); System.out.println("\n"); break; case "-x": switchflag =false; break; default: System.out.println("輸入了無效的操作符\n"); System.out.println("\n"); break; } } System.out.println("程序結束"); }
}
四、效果
目標文件E:/www/cd.txt 這是一個保存了java代碼的文件,其中包含空行,代碼行和注釋行。
package com.dyf.io.BufferedChar; /** * 使用字符緩沖流實現純文本文件的copy * BufferReader(),BufferWriter(); * */ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyFile { public void copy(File src,File dest){ BufferedReader bReader =null; BufferedWriter bWriter = null; try { bReader = new BufferedReader(new FileReader(src)); bWriter = new BufferedWriter(new FileWriter(dest)); String line = null; while(null != (line = bReader.readLine())){ bWriter.write(line); bWriter.newLine(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try { bReader.close(); bWriter.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
實現功能
獲得單詞數信息:
獲得行數信息:
獲得當前文件的所有信息:
遍歷某一文件夾並獲得所有文件的信息:
五、拓展功能,寫出文件
具體代碼如下:
/** * 該方法用於將一個FileInfo對象的所有字段寫到 destPath這個文件路徑下 * @param info:FileInfo * @param destPath : 目標路徑 */ public void writeLine(FileInfo info,String destPath){ BufferedWriter bWriter = null; File file = new File(destPath+"/info.txt"); try { bWriter = new BufferedWriter(new FileWriter(file)); bWriter.write("CharsNum:"+info.getCharsNum()+'\n'); bWriter.newLine(); bWriter.write("LinesNum:"+info.getLinesNum()+"\n"); bWriter.newLine(); bWriter.write("WordsNum:"+info.getWordsNum()+'\n'); bWriter.newLine(); bWriter.write("CodeLine:"+info.getCodeLine()+'\n'); bWriter.newLine(); bWriter.write("CommtLine:"+info.getCommtLine()+'\n'); bWriter.newLine(); bWriter.write("EmptyLine:"+info.getEmptyLine()+'\n'); bWriter.flush(); } catch (IOException e) { System.out.println("寫出文件失敗"); }finally{ if(bWriter!=null){ try { bWriter.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
效果展示 :