Download presentation
Presentation is loading. Please wait.
1
副程式概念與 檔案存取 函式與傳值 重構觀念 串流資料 檔案資料存取
2
副程式與重構概念 重構(Refactory) 副程式(Subprogram)
將程式中具有特定功能的部分獨立出來成為類別方法或副程式,而主程式的部份則呼叫這些方法或副程式出來使用,其目的便是要讓程式更具結構化。 副程式(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.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) / ; 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) / ; 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) / ; return f ; public static double FtoC(double f) {// 溫度轉換公式 F -> C double c = (f ) * 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++; // 計數器變數加一
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)) % ; 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) ;
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 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[]") ; System.out.println(a[i] + "\t" + b[i]) ; 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] ; */ b[i] = b[i] * 10 ; return b ;
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: 代表檔案名稱,包含絕對路徑 顯示資料夾資訊 建立資料夾目錄的方法 更改檔案或資料夾名稱的方法 刪除檔案的方法 boolean isDirectory()-檢視參數str所代表的資訊是否為一個目錄 String[] list()-如果參數str為一個目錄,將目錄下所有的檔名存在一個字串陣列裡 File[] listFiles()-將目錄下所有的檔案存在一個檔案陣列裡,即陣列裡的每一個元素均記錄著檔案相關資訊 boolean mkdir()-建立新資料夾 boolean delete()-刪除檔案 boolean renameTo(File dest)-更換檔名為dest
19
顯示檔案資訊 boolean exists()-判斷檔案或資料夾是否存在 isFile()-判斷是否是一個檔案 String
getAbsolutePath()-取得絕對路徑 getName()-取得檔名字串 getPath()-取得所在位置相對路徑 long length()-傳回檔案大小 canRead()-判斷檔案是否可被讀取 canWrite()-判斷檔案是否可以覆寫 lastModified()-傳回檔案最後一次修改的時間 setReadOnly()-設定檔案為唯讀
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
檔案資料讀取-利用Scanner Scanner 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(),表示一次讀一個字串 如果不是純文字文件(如Word、PDF文件等、多媒體影音檔),則需用FileInputStream及 FileOutputStream處理。
22
Unicode文件資料存取- 含有特殊字元的檔案須用unicode或utf-8格式,其檔頭無法直接被Scanner讀取,須略過或以存取串流資料的方式處理 以下操作須在try … catch區塊中 利用Scanner略過檔頭字串(不能在DOS狀態下執行) File f = new File(filename);//宣告資料檔物件 Scanner sc = new Scanner(f); sc.skip("");//避開檔頭字元在netbeans中或可編輯UTF-8文件之編輯器中可看到 //開始讀取資料 利用BufferedReader緩衝串流讀取文件資料 File f = new File(filename);//宣告資料檔物件 BufferedReader read = new BufferedReader( new InputStreamReader( new FileInputStream(f), “UTF-8”)); read.skip(1);//避開檔頭字元 read.readLine();//讀取一列字串(如前面無skip指令則會連檔頭一併讀取) 利用BufferedWriter寫入文件資料 File f = new File(filename);//宣告輸出資料檔物件 BufferedWriter out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(f), encoding));//宣告串流物件 在緩衝資料寫入器中指定輸出串流寫入器,包含輸出串流檔和編碼 out.write(str+"\n");//寫入資料 out.close();//關閉串流檔
23
位元檔案串流處理- 對於非文字的檔案存取,java.io套件的函式庫提供了處理位元組檔案串流的類別,FileInputStream與FileOutputStream,來處理讀取和寫入位元組或位元組陣列(參考java.io.InputStream及java.io.OutputStream),將檔案內容以二進位元逐一進行存取。物件宣告如下 FileInputStream fis = new FileInputStream(filename) ; FileOutputStream fos = new FileOutputStream(filename) ; filename: 代表輸入或輸出的檔案(型態為File)或檔名字串(型態為String) 存取結束時均要做封裝(使用close()方法) 使用此物件時,必須在try…catch例外處理區塊中 存取資料時,要設定緩衝區暫存讀取的二進位位元組(byte[]),再利用物件類別提供的read與write方法從緩衝區讀寫資料,直到所有資料讀完為止。 一般複製檔案時常用此種處理方式,備份如圖檔、影像等文件。
24
複製二進位元檔案(以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) {}
25
檔案存取範例 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) ; 檔案存取範例
26
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" ; if(fname.canRead()) dir = dir + "r" ; if(fname.canWrite()) dir = dir + "w" ; if(fname.isHidden()) dir = dir + "h" ; 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") ;
27
// 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 ; if(fcopy.exists()) { fw = new FileWriter(fcopy,true) ; } else { fcopy.createNewFile() ; fw = new FileWriter(fcopy) ; fw.write(sc.nextLine()+"\n") ; fw.close() ;
28
// 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");
29
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) {}
30
存取UTF-8格式檔案 import java.io.BufferedReader; import java.io.File;
import java.io.FileInputStream; import java.io.InputStreamReader; public class ReadFileTest { public static void main(String[] args) { String title = ""; int n = 0; double[] x = null; double[] y = null; File fin = new File("testdata_utf8.txt"); if (f.exists()) { try { BufferedReader read = new BufferedReader( new InputStreamReader( new FileInputStream(fin), “UTF-8”));//讀取UTF8格式檔案
31
read.skip(1);//避開檔頭字元 title = read.readLine();//讀取標題 n = Integer.parseInt(read.readLine());//讀取資料數 x = new double[n]; y = new double[n]; for (int i = 0; i < n; i++) {//讀取數據資料格式如0,100-->用,號分開 String strData = read.readLine(); x[i] = Double.parseDouble(strData.split(",")[0]);//x軸資料 y[i] = Double.parseDouble(strData.split(",")[1]);//y軸資料 }//結束for迴圈 }//結束if判斷 } catch (Exception ex) { } //測試讀到的資料(如檔案不存在則輸出title預設值為空字串) System.out.println(title); for (int i = 0; i < n; i++) { System.out.println(x[i] + "\t" + y[i]);
32
//寫入UTF-8格式檔案 File f = new File("testoutput_utf8.txt"); try { BufferedWriter out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(f), “UTF-8")); out.write(str+"\n"); out.close(); } catch(Exception ex) { }
Similar presentations