1 / 28

副程式概念與 檔案 存取

副程式概念與 檔案 存取. 函式與傳值 重構觀念 串流資料 檔案資料存取. 副程式與重構概念. 重構 (Refactory) 將程式中具有特定功能的部分獨立出來成為類別方法或副程式,而主程式的部份則呼叫這些方法或副程式出來使用,其目的便是要讓程式更具結構化。 副程式 (Subprogram) 主要分為兩種, 一種是宣告為 void 而沒有傳回值的函式 (Subroutine) , 一種則是宣告為變數型態必須有 return 指令傳回計算值的函數 (Function) 。 此概念在物件導向設計裡,則衍生為類別中的方法 (Method) 。

ricky
Download Presentation

副程式概念與 檔案 存取

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 副程式概念與檔案存取 函式與傳值 重構觀念 串流資料 檔案資料存取

  2. 副程式與重構概念 • 重構(Refactory) • 將程式中具有特定功能的部分獨立出來成為類別方法或副程式,而主程式的部份則呼叫這些方法或副程式出來使用,其目的便是要讓程式更具結構化。 • 副程式(Subprogram) • 主要分為兩種, • 一種是宣告為void而沒有傳回值的函式(Subroutine), • 一種則是宣告為變數型態必須有return指令傳回計算值的函數(Function)。 • 此概念在物件導向設計裡,則衍生為類別中的方法(Method)。 • 主程式可定義為Java類別中一個名為main的函式,其傳入的引數為一個字串陣列。 • 傳入副程式的引數除非是傳入位址,例如陣列的傳址,否則傳入的值並不會隨著副程式的計算而改變。

  3. Example – 以Ex02_LoopControl為例重構成以下之副程式 • forLoop(): 測試for迴圈 • 測試for迴圈 • ConvertTemp(double cButtom, double cTop, int n) : 溫度對照表 • 輸入攝氏溫度上下限,分成n個刻度,建立攝氏華式溫度表 • 建立換算溫度函數(CtoF(), FtoC)計算溫度 • FoldRope(float ropeLen, float sectLen) : 繩索對折次數計算 • 輸入繩索長度ropeLen及對折後長度sectLen,印出對折次數 • errorIncrement(double iniValue, double limValue) : 浮點數迭加 • 代入iniValue初始值,連續迭加至上限值limValue,觀察累計誤差 • nFactorial(int n) : 階乘計算函數 • 代入一整數參數n後得到n!階乘之值 • Table99() : 九九乘法表 • 建立九九乘法表 • Lotto() : 樂透彩自動選號 • 副程式中改以陣列型態產生一組號碼 • 且將排序部份程式改為函數(BubbleSort) • 主程式呼叫此副程式時利用迴圈產生多組號碼

  4. 副程式重構範例 public class Ex04_Refactory { public static void main(String[] args) { System.out.println("測試for迴圈"); forLoop() ; System.out.println("溫度對照表"); ConvertTemp(20, 100, 10) ; System.out.println("繩索對折次數計算"); FoldRope(100f, 20f) ; System.out.println("浮點數迭加 – 誤差累計"); errorIncrement(0.1, 100) ; System.out.println("階乘計算"); System.out.println("5!=" + nFactorial(5)) ; System.out.println("九九乘法表"); Table99() ; System.out.println("樂透彩自動選號"); for(int i=0; i<6; i++) { System.out.println("第"+(i+1)+"組號碼"); Lotto() ; } }

  5. public static void forLoop() {// 測試for迴圈 int total = 0; // 遞增for迴圈敘述 for (int i = 1; i <= 10; i++ ) { System.out.print("Number: " + i + " "); total += i; } System.out.println("\nSummary from 1 to 10: " + total); System.out.println(" ----------------- "); total = 0; // 重設總和變數 // 遞減for迴圈敘述 for (int i = 10; i >= 1; i-- ) { System.out.print("Number: " + i + " "); total += i; } System.out.println("\nSummary from 10 to 1: " + total); }

  6. // 溫度對照表 public static void ConvertTemp(double cButtom, double cTop, int n) { double c = cButtom ; double f; System.out.println("C F"); // while迴圈敘述 // while ( c <= 100 ) { // f = (9.0 * c) / 5.0 + 32.0; while ( c <= cTop ) { f = CtoF(c) ; System.out.println(c + " " + f); // c += 10; c+=(cTop-cButtom)/n ; } }

  7. // 溫度對照表 public static void ConvertTemp(double cButtom, double cTop, int n) { double c = cButtom ; double f; System.out.println("C F"); // while迴圈敘述 // while ( c <= 100 ) { // f = (9.0 * c) / 5.0 + 32.0; while ( c <= cTop ) { f = CtoF(c) ; System.out.println(c + " " + f); // c += 10; c+=(cTop-cButtom)/n ; } } public static double CtoF(double c) {// 溫度轉換公式 C -> F double f = (9.0 * c) / 5.0 + 32.0; return f ; } public static double FtoC(double f) {// 溫度轉換公式 F -> C double c = (f - 32.0) * 5.0 / 9.0 ; return c ; }

  8. // 繩索對折次數計算 public static void FoldRope(float ropeLen, float sectLen) { int count = 0; // 計算次數 // float len = 100.0f; float len = ropeLen ; // do/while迴圈敘述 do { System.out.println(count + " Length: " + len); count++; len /= 2.0; // 對折繩索 } while ( len > sectLen ); System.out.println("Folding Number: " + count); System.out.println("Final Length: " + len); }

  9. // 浮點數迭加 – 誤差累計 public static void errorIncrement(double iniValue, double limValue) { // double d=0.1; double d = iniValue ; double sum=0.0; // while(d<=10.0){ while(d<=limValue){ sum=sum+d; System.out.println(d +"\t"+sum + "\t" + Math.round(sum*100)/100.0); d = d + 0.1; } }

  10. public static int nFactorial(int n) {// 階乘計算 int num = n; int prod = 1; int count = 1 ; // do/while迴圈敘述 do { System.out.println("Number: " + count); if (num == 0) break ; // 跳出迴圈 else prod *= count; count++; } while ( count <= num ); // System.out.println("5! = " + prod); return prod ; }

  11. public static void Table99() {// 九九乘法表 // 顯示標題列 System.out.print(" "); for (int i = 1; i <= 9; i++ ) System.out.print(i + " "); System.out.println(); // 巢狀迴圈-第一層while迴圈 int row = 0, col=0 ; while (row <= 9 ) { // 顯示欄標題 System.out.print(row + " "); for (col = 1; col <= 9; col++ ) { // 第二層for迴圈 System.out.print(row + "*" + col + "="); System.out.print(row*col + " "); if ( (row*col ) < 10 && col != 1 ) System.out.print(" ");// 調整顯示位置 } row++; // 計數器變數加一 System.out.println(); } }

  12. public static void Lotto() {// 樂透彩自動選號 int[] lo = new int[6] ; boolean check ; int k = 1; do { for(int i=0; i<6; i++) lo[i] = ((int)(Math.random() * 1000)) % 49 + 1; check = false; for(int i=0; i<6; i++) { for(int j=i+1; j<6; j++) { if(lo[i] == lo[j])check = true ; } } k++ ; } while(check) ; System.out.print("重號次數:" + k + "\n樂透號碼:") ; for(int i=0; i<6; i++)System.out.print(lo[i] + "\t") ; System.out.println() ; System.out.print("重新排序:") ; BubbleSort(lo) ; for(int i=0; i<6; i++)System.out.print(lo[i] + "\t") ; System.out.println() ; }

  13. public static int[] BubbleSort(int[] lo) {// 氣泡排序 for(int i=0; i<lo.length-1; i++) { for(int j=i+1; j<lo.length; j++) { if(lo[i] > lo[j]) { int big = lo[i] ; lo[i] = lo[j] ; lo[j] = big ; } } } return lo ; } }

  14. 傳址與傳值 • 變數與位址資料 • 變數資料存於位址上,不同的變數可能指向同一個位址。 • 當資料值改變時,表示使用相同位址的不同變數值會一起改變。 • 唯有將不同變數指向不同位址時,變數的資料才各自獨立。 • 副程式的資料傳遞 • Java的設計上省略了C/C++的指標(pointer)運算,直接應用位址與數值的傳送存取副程式資料 • 純量變數的資料傳送是把數值傳入副程式,輸入變數和副程式引數佔不同的位址 • 陣列變數資料的傳送是把位址傳入副程式,輸入變數和副程式引數使用相同位址 • 使用副程式處理輸入引數時,如果要得到運算後的純量變數,或希望保留原始陣列,則應利用函數的傳回值進行處理 • 利用等號( = )讓不同的陣列變數對應到同一位址 • 利用陣列物件的clone()方法將陣列資料複製到不同的位址

  15. public static void setA(int a0, int[] a) { a0 = a0 * a0 ; for(int i=0; i<a.length; i++) { a[i] = a[i] * 10 ; } } public static int getA(int a0) { return a0*a0 ; } public static int[] getB(int[] a) { int[] b = a.clone() ; /* 複製陣列, 與clone同義 int[] b = new int[a.lenght] ; for(int i=0; i<b.length; i++) { b[i] = a[i] ; } */ for(int i=0; i<b.length; i++) { b[i] = b[i] * 10 ; } return b ; } public static void main(String[] args) { int ia = 10 ; int ib = ia ; ia = 20 ; System.out.println("ia="+ia+"\tib="+ib) ; int[] a = {1, 4, 3, 5, 9} ; setA(ia, a) ; System.out.println("a[] --> changed in setA") ; for(int i=0; i<a.length; i++) { System.out.print(a[i] + "\t") ; } System.out.println("ia = " + ia) ; ib = getA(ia) ; System.out.println("Use getA to return new value - input: " + ia + "\treturn: " + ib) ; int[] b = getB(a) ; System.out.println("Use getB to return new value of input a[]\na[]\tb[]") ; for(int i=0; i<a.length; i++) { System.out.println(a[i] + "\t" + b[i]) ; } }

  16. 檔案資料處理 • 資料串流 • 串流(stream)觀念最早使用在UNIX作業系統,串流模型如同水管的水流,並沒有考慮資料來源、型態等,當程式開啟一個來源的輸入串流(例如檔案、記憶體和緩衝區等)為循序存取串流(Sequential Access Streams),如水流般依序讀取和寫入資料。 • Java提供了一套用來處理串流資訊的函式套件,Java I/O套件,全名是Java Input/Output(輸入/輸出),即應用程式的資料輸入與輸出,在Java類別函式庫(Class Library)是使用串流模型來處理資料的輸入與輸出,基本上Java串流類別分成兩大類: • 字元串流(CharacterStream) • 位元組串流(ByteStream)

  17. 字元串流(CharacterStream)- • 字元串流是是一種適合人類閱讀(Human-readable)的串流,Reader/Writer兩個類別分別讀取和寫入16位元的字元資料。 • BufferReader/BufferWriter:處理緩衝區I/O。 • InputStreamReader/OutputStreamWriter:InputStreamReader在讀取位元組資料後將它轉成字元資料,OuputStreamWriter是將字元轉換成位元組資料。 • FileReader/FileWriter:處理檔案的I/O。 • 位元組串流(ByteStream)- • 位元組串流是一種電腦格式(Machine-formatted)串流,可以讀取和寫入8位元的位元組資料,也就是處理二進位資料的執行檔、圖檔和聲音等。 • FileInputStream/FileOutputStream:處理檔案的I/O。 • DataInputStream/DataOutputStream:讀取和寫入基本資料型態的資料。 • BufferInputStream/BufferedOutputStream:處理緩衝區I/O。

  18. 檔案(File)與資料夾目錄(Directory)處理- • File物件-java.io套件提供File類別(java.io.File)建立物件,取得檔案或資料夾的相關資訊,例如取得檔名、檔案大小、檔案路徑、檔案屬性或目錄下之檔案列表等,物件宣告如下File f = new File(String str) ; • String str: 代表檔案名稱,包含絕對路徑 • 顯示資料夾資訊 • 建立資料夾目錄的方法 • 更改檔案或資料夾名稱的方法 • 刪除檔案的方法

  19. 顯示檔案資訊

  20. 一般文字檔案串流處理- • FileWriter物件-java.io套件提供FileWriter類別(java.io.FileWriter)建立物件,來處理文字檔案的串流,物件宣告如下FileWriter fw = new FileWriter(File f, true) ; • File f: 代表被宣告的檔案物件變數 • true: 省略時表示覆蓋檔案物件f的內容,不省略則表示從檔案尾端附加新的字元串流 • 使用FileWriter時,必須在try…catch例外處理區塊中 • 常用的檔案寫入方式File f = new File(“filename.txt”) ;FileWriter fw ;try { if(fcopy.exists()) {// 如果檔案存在則於尾部附加文字資料fw = new FileWriter(f, true) ; } else {// 如果檔案不存在則建立新檔f.createNewFile() ; fw = new FileWriter(f) ; } fw.write(str + “\n”) ; // 將str字串變數資料寫入檔案並換行fw.close() ; // 結束檔案寫入動作} catch(Exception e) {}

  21. 檔案資料讀取-利用ScannerScanner sc = new Scanner(File filename) ; • 必須在try … catch區塊中使用 • 利用Scanner讀檔方式File f = new File(“filename.txt”) ;Scanner sc ;try { sc = new Scanner(f) ; while(sc.hasNext()) { System.out.println(sc.nextLine()) ; }} catch(Exception e) {} • while迴圈中的條件判斷會先確認文件中有出現字串資料後再讀取資料,如使用sc.hasNextLine()則表示先檢查是否有整列資料(以分行符號作為分隔) • 使用sc.nextLine()表示一次讀取整列資料,亦可使用sc.next(),表示一次讀一個字串 • 如果不是一般文字,則需用FileInputStream及FileOutputStream進行處理。

  22. 位元檔案串流處理- • 對於非文字的檔案存取,java.io套件的函式庫提供了處理位元組檔案串流的類別,FileInputStream與FileOutputStream,來處理讀取和寫入位元組或位元組陣列(參考java.io.InputStream及java.io.OutputStream),將檔案內容以二進位元逐一進行存取。物件宣告如下FileInputStream fis = new FileInputStream(filename) ;FileOutputStream fos = new FileOutputStream(filename) ; • filename: 代表輸入或輸出的檔案(型態為File)或檔名字串(型態為String) • 使用此物件時,必須在try…catch例外處理區塊中 • 存取資料時,要設定緩衝區暫存讀取的二進位位元組,再利用物件類別提供的read與write方法從緩衝區讀寫資料,直到所有資料讀完為止。 • 一般複製檔案時常用此種處理方式,備份如圖檔、影像等文件。

  23. 複製二進位元檔案(以Word檔為例)try { FileInputStream fis = new FileInputStream(new File("wordtest.doc" )); FileOutputStream fos = new FileOutputStream(new File("wordtest_bak.doc" )); int filesize = fis.available() ; byte[] buffer = new byte[1024] ; while(true) { if(fis.available() < 1024) { int remain ; do { remain = fis.read() ; fos.write(remain); } while(remain != -1) ; break ; } else { fis.read(buffer) ; fos.write(buffer) ; } } fis.close() ; fos.close() ;} catch (Exception e) {}

  24. import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.util.Date; import java.util.Scanner; public class Ex04_FileTest { public static void main(String[] args) { // File and directory property String filepath = "H:\\Course_Data\\CompLang\\JavaExample\\src\\" ; String filename = "testfile.txt" ; File f = new File(filename) ; if(f.exists()) { System.out.println(f.getName()) ; System.out.println(f.getPath()) ; System.out.println(f.getAbsolutePath()) ; } else { System.out.println("The file is not existing") ; } String[] filenames ; File fs = new File(filepath) ; 檔案存取範例

  25. if(fs.isDirectory()) { filenames = fs.list() ; for(int i=0; i<filenames.length; i++) { File fname = new File(filenames[i]) ; String dir = "[" ; if(fname.isDirectory()) dir = dir + "d" ; else dir = dir + "-" ; if(fname.isFile()) dir = dir + "f" ; else dir = dir + "-" ; if(fname.canRead()) dir = dir + "r" ; else dir = dir + "-" ; if(fname.canWrite()) dir = dir + "w" ; else dir = dir + "-" ; if(fname.isHidden()) dir = dir + "h" ; else dir = dir + "-" ; dir = dir + "]" ; long time = fname.lastModified() ; Date date = new Date(time) ; System.out.print(dir + "\t" + filenames[i] + "\t" + fname.length() + " Bytes\t" + date + "\n") ; } } else { System.out.println("It is not a directory") ; }

  26. // Read text file Scanner sc ; try { sc = new Scanner(f) ; while(sc.hasNext()) { System.out.println(sc.nextLine()) ; } } catch(Exception e) {} // Write text file File fcopy = new File(filepath + "testcopy.txt"); FileWriter fw ; try { if(fcopy.exists()) { fw = new FileWriter(fcopy,true) ; } else { fcopy.createNewFile() ; fw = new FileWriter(fcopy) ; } sc = new Scanner(f) ; while(sc.hasNext()) { fw.write(sc.nextLine()+"\n") ; } fw.close() ; } catch(Exception e) {}

  27. // Rename file String newfname = filepath + "testnew.txt" ; fcopy.renameTo(new File(newfname)) ; // Delete file fcopy.delete() ; // Clone file String srcName = filepath + "wordtest.doc" ; String tarName = filepath + "wordtest_bak.doc" ; try { FileInputStream fis = new FileInputStream(new File(srcName)); FileOutputStream fos = new FileOutputStream(new File(tarName)); int filesize = fis.available() ; byte[] buffer = new byte[1024] ; System.out.println(filesize + " bytes are copying");

  28. while(true) { if(fis.available() < 1024) { int remain ; do { remain = fis.read() ; fos.write(remain); } while(remain != -1) ; break ; } else { fis.read(buffer) ; fos.write(buffer) ; } System.out.println(fis.available() + " bytes are left"); } fis.close() ; fos.close() ; } catch (Exception e) {} } }

More Related