翻轉工作室:粘添壽
第六章 檔案輸入與輸出運用
6-1 檔案輸入/輸出模式
資訊系統大多需要檔案來儲存資料。當使用者輸入建立資料之後,需將所登錄的資料儲存到檔案內,下次管理資料時再由檔案讀入原來資料,如此才能管理龐大資料量。檔案是資料儲存於磁碟機的空間結構,不同的儲存結構也可能影響到資料存取效率,也需要相對應的存取方法來配合。一般資訊系統的檔案型態可區分為順序檔案與紀錄檔案兩大類,前者大多採用串流存取模式;後者大多採用緩衝器存取技巧。以下分別介紹這兩種檔案型態的特性與宣告產生方式。
6-1-1 順序檔案與串流讀寫
將資料依序寫入、讀出檔案。好像錄製錄音帶一樣,由起頭開始依序寫入磁帶,最後標示一個特殊記號表示結束,讀出時也要從頭開始順序讀取,此種儲存檔格式稱為『順序檔案』(Sequence File)。簡單的說,順序檔案允許資料以連串方式,一點一滴依序寫入磁碟檔案內,也允許一點接一點依序由檔案讀出,吾人則將此存取技巧稱之為『串流』(stream)讀寫。早期順序檔案主要是針對磁帶機的存取方式,但最近網路運用普遍,電腦之間透過網路傳輸資料,大多不喜歡資料傳輸完畢後,再執行下一步驟的處理,大多希望一邊傳輸資料,一邊處理已傳輸部分資料,資料全部傳輸完畢後,也剛好全部處理完畢。譬如,收聽網站上音樂,音樂檔案必須由網站下載到個人電腦上,再由個人電腦撥放該音樂檔案。我們當然希望一邊傳輸音樂檔案,一邊撥放該音樂,全部傳輸完畢後,也剛好收聽完畢,因此就必須利用順序格式讀取音樂檔案,這就是串流的概念。其實,網路上除了音樂檔案之外,無論是視訊、動畫、影像等等檔案也大多如此。也就是說,多媒體檔案大多採用順序檔案格式與串流存取方式,尤其透過網路傳輸也顯得需要。
圖 6-1 串流檔案輸入/輸出物件
順序檔案是利用串流(Stream)方式,連續性的寫入或讀出。產生檔案時必須宣告它成為串流輸入/輸出檔案;另一方面,也必須將寫入檔案的記憶體資料宣告成串流型態。圖 6-1 是將 Employee.data 檔案宣告成串流輸入/輸出檔案,並產生串流輸入/輸出通道。
6-1-2 紀錄檔案與緩衝器讀寫
描述真實環境現象的資料大多有一定的規範,每樣事件大多由一筆資料記載它的屬性,此筆資料就稱為『紀錄』(Record)。記載許多事件而必須寫入磁碟檔案時,就需要一筆紀錄接一筆,將紀錄依序寫入檔案系統,此格式則稱為『紀錄檔案』(Record file)。一般作業系統為了提高效益,並不立即將紀錄寫入檔案內,而是將紀錄資料組裝成『緩衝器』(Buffer)格式,暫存於主記憶體的某一固定空間內,等待電腦較有空閒或已累積多筆『緩衝器』資料時,再一併寫入檔案(或稱磁碟機)。由檔案讀出資料也是一樣,電腦一次由磁碟檔案裡讀出多筆『緩衝器』資料(儲存於主記憶體內),再依序由『緩衝器』讀入執行中的程式。一次讀取一筆資料模式大多運用於管理資訊系統的大量資料儲存。也就是說,一般『電子化』管理系統的資料儲存大多採用記錄檔案格式與緩衝器存取模式。
簡單的說,紀錄檔案的存取都需透過緩衝器的運作,因此宣告順序檔案物件時,也須宣告緩衝器物件,並將兩者連結起來成為『程式』的輸入/輸出檔案物件。圖 6-2 為產生紀錄檔案的宣告方式,它是屬於 java.io 套件的類別。以下分別說明輸入與輸出檔案的宣告方法。
圖 6-2 紀錄檔案輸入/輸出物件
6-2 記錄檔案的存取介面
6-2-1 檔案寫入介面
宣告可寫入記錄檔案的命令(檔案為 Employee.data),與相關存取方法如下:(如圖 6-2)
宣告『可寫入』紀錄檔案的語法範例: |
功能說明: |
import java.io.*; |
導入 java.io 套件 |
String file = “Employee.data” |
檔案名稱(範例:Employee.data) |
FileWriter fw = new FileWriter(file); |
產生可供寫入的紀錄檔案 |
BufferedWriter bw = new BufferedWriter(fw); |
產生可供寫入的緩衝器 |
void bw.write() |
將字元、字串或位元寫入檔案。 |
void bw.flush() |
強迫寫入檔案。 |
void bw.newLine() |
於檔案內開啟新行(行分隔)。 |
void bw.close() |
關閉檔案。 |
重點說明如下:
6-2-2 檔案輸出介面
產生可讀取檔案與可寫入檔案的步驟大致上相同。以 Employee.data 檔案為例,產生的宣告步驟如下:(如圖 6-2 所示)
宣告『可讀取』紀錄檔案的語法範例: |
功能說明: |
import java.io.*; |
導入 java.io 套件 |
String file = “Employee.data” |
檔案名稱(範例:Employee.data) |
File fileID = new File(file); |
開啟檔案,並回傳檔案識別碼 |
FileReader fr = new FileReader(fileID); |
產生可供讀取的紀錄檔案 |
BufferedReader br = new BufferedReader(fr); |
產生可供讀取的緩衝器 |
bw.read() |
緩衝器讀取方法之一 |
重點說明如下:
檔案物件的方法: |
說明: |
boolean canRead() |
測試檔案是否可讀取。 |
boolean canWrite() |
測試檔案是否可寫入。 |
boolean exists() |
測試檔案是否存在 |
boolean isFile() |
測試是否是一般檔案。 |
『可讀取』檔案的方法: |
說明: |
void close() |
關閉檔案。 |
void mark() |
於檔案內標示某一位置。 |
int read() |
讀取以字串或位元組格式讀取檔案。 |
String readLine() |
由檔案讀取一行(或一筆)紀錄。 |
void reset() |
重置檔案回標示位置。 |
6-3 紀錄檔案的輸出運用
6-3-1 物件陣列與記錄檔案
電子化管理系統的資料大多有固定格式,每一筆資料就成為一個紀錄。譬如,某一公司的員工管理系統,每一筆紀錄登錄一位員工的資料;也依照系統需求,每一筆資料由若干個屬性所構成。紀錄型態資料大多以一筆接一筆紀錄型態儲存於檔案內,資料系統需要處理這些資料時,再由紀錄檔案讀入主機電腦的記憶體內。然而,紀錄資料於記憶體內儲存方式又有許多格式,譬如陣列、樹狀或鏈路格式等等,即是資料結構的型態。
圖 6-3 為紀錄檔案與陣列資料之間的存取方法。每一陣列元素是一筆紀錄資料(物件變數),其中包含了若干屬性的變數資料。陣列資料輸出到紀錄檔案是方法是,每筆資料是一個屬性接一個屬性寫入,屬性之間利用一個分隔符號(Delimit)區分,可能是『tab』(\t)空白鍵、分號(;)或單一空白鍵等等。一筆資料輸出完畢後,再跳到下一行繼續輸出,與輸出到螢幕的方法非常類似。
圖 6-3 陣列內物件變數輸出到紀錄檔案
6-3-2 範例研討:登錄員工資料
(A)程式功能:Ex6_1.java
請幫志明電器製造公司建立一套人事管理系統,該系統允許輸入員工資料,並儲存於資料檔案內(Human.data)。假設登錄員工資料包含有:員工代號(int)、姓名(String)、工作部門(String)、底薪(int)、職務加級(int)。期望操作介面,以及檔案輸出結果如下:
G:\Examples\chap9\Ex6_1>java Ex6_1 是否繼續輸入員工資料 (yes/no) =>yes ***** 輸入員工資料 ***** 輸入員工姓名 =>陳中心 輸入所屬部門 =>倉管課 輸入員工代號 =>71219 輸入員工底薪 =>32000 輸入薪資加級 =>17000 是否繼續輸入員工資料 (yes/no) =>yes ***** 輸入員工資料 ***** 輸入員工姓名 =>劉明新 輸入所屬部門 =>行銷課 輸入員工代號 =>71242 輸入員工底薪 =>31000 輸入薪資加級 =>15000 是否繼續輸入員工資料 (yes/no) =>no ***** 將員工資料輸出到 Human.dada 檔案內 **** ***** 輸出完畢 ****
G:\Examples\chap9\Ex6_1>dir/b Employee.class Human.data Ex6_1.java Ex6_1.class
G:\Examples\chap9\Ex6_1>type Human.data 【type 顯示檔案內容命令】 71219 陳中心 倉管課 32000 17000 71242 劉明新 行銷課 31000 15000 |
(B)製作技巧研討:
本系統製作要點是,宣告產生一個物件陣列,將連續輸入的員工資料寫入其中,輸入完畢之後,再將物件陣列內容一筆接一筆寫入輸出檔案上。須注意的是,輸出檔案上每一行存放一筆員工資料,資料的每個屬性分別由一個欄位表示。虛擬碼提示如下:
宣告物件陣列的類別(Employee.data); 主類別(Ex6_1)範圍:{ 宣告產生物件陣列(Employee[] worker;); 宣告輸出檔案物件: String file = "Human.data"; BufferedWriter data = new BufferedWriter(new FileWriter(file)); 連續讀取多筆員工資料並存入物件陣列中(while() { …}); 將物件陣列輸出到檔案; } |
(C)程式範例:
圖 6-4 Ex6_1 程式架構
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//Ex6_1.java /*系統允許輸入員工資料,並儲存於資料檔案內(Human.data) */
import java.util.Scanner; import java.io.*; class Employee { /* 物件陣列的類別宣告 */ int ID; // 員工代號 String name; // 員工姓名 String depart; // 所屬部門 int payment; // 底薪 int duty; // 職務加級 }
public class Ex6_1 { public static void main(String args[]) throws IOException { Scanner keyin = new Scanner(System.in); Employee[] worker = new Employee[20];
/* 宣告輸出檔案物件 */ String file = "Human.data"; BufferedWriter data = new BufferedWriter(new FileWriter(file)); int k=0; String sel;
/* 讀入資料並存入物件陣列內 */ System.out.printf("是否繼續輸入員工資料 (yes/no) =>"); sel = keyin.nextLine(); while(sel.equals("yes") && (k <20)) { worker[k] = new Employee(); System.out.printf("***** 輸入員工資料 *****\n"); System.out.printf("輸入員工姓名 =>"); worker[k].name = keyin.nextLine(); System.out.printf("輸入所屬部門 =>"); worker[k].depart = keyin.nextLine(); System.out.printf("輸入員工代號 =>"); worker[k].ID = keyin.nextInt(); System.out.printf("輸入員工底薪 =>"); worker[k].payment = keyin.nextInt(); System.out.printf("輸入薪資加級 =>"); worker[k].duty = keyin.nextInt(); keyin.nextLine(); // 清除鍵盤輸入 System.out.printf("是否繼續輸入員工資料 (yes/no) =>"); sel = keyin.nextLine(); k = k+1; }
/* 將物件陣列內容寫入檔案內 */ System.out.printf("*** 將員工資料輸出到 Human.dada 檔案內 **\n"); for (int i=0; i<k; i++) { data.write(worker[i].ID + "\t"); data.write(worker[i].name + "\t"); data.write(worker[i].depart + "\t"); data.write(worker[i].payment + "\t"); data.write(worker[i].duty + "\n"); } data.close(); System.out.printf("***** 輸出完畢 ****\n"); } } |
(D) 程式重點說明:
6-3-3 自我挑戰:超商列印購物清單
(A)程式功能:PM6_1.java
擴充範例 Ex5_4.java程式功能(本書第五章)。請擴充『春嬌生鮮超市』販賣系統的功能,除了可由螢幕點選客人購買商品與數量外,最後可由螢幕顯示總購買金額,並印出收據(寫入檔案)。假設僅販賣:可口餅乾(20 元)、味全鮮乳(30 元)、御便當(50 元)、黑松汽水(20 元)、頻果西打(30 元)與脆笛酥(20 元),期望操作介面如下:
D:\Java2_book\chap6\PM6_1>javac PM6_1.java
D:\Java2_book\chap6\PM6_1>dir/b Element.class List.data PM6_1.class PM6_1.java D:\Java2_book\chap6\PM6_1>java PM6_1 **** 歡迎光臨 春嬌超商 請選擇購買商品 **** (1) 可口餅乾 20 元 (2) 味全鮮乳 30 元 (3) 御便當 50 元 (4) 黑松汽水 20 元 (5) 頻果西打 30 元 (6) 脆笛酥 20 元 (7) 結算金額 請輸入選項 =>1 購買數量 =>24 **** 歡迎光臨 春嬌超商 請選擇購買商品 **** (1) 可口餅乾 20 元 (2) 味全鮮乳 30 元 (3) 御便當 50 元 (4) 黑松汽水 20 元 (5) 頻果西打 30 元 (6) 脆笛酥 20 元 (7) 結算金額 請輸入選項 =>3 購買數量 =>15 **** 歡迎光臨 春嬌超商 請選擇購買商品 **** (1) 可口餅乾 20 元 (2) 味全鮮乳 30 元 (3) 御便當 50 元 (4) 黑松汽水 20 元 (5) 頻果西打 30 元 (6) 脆笛酥 20 元 (7) 結算金額 請輸入選項 =>5 購買數量 =>8 **** 歡迎光臨 春嬌超商 請選擇購買商品 **** (1) 可口餅乾 20 元 (2) 味全鮮乳 30 元 (3) 御便當 50 元 (4) 黑松汽水 20 元 (5) 頻果西打 30 元 (6) 脆笛酥 20 元 (7) 結算金額 請輸入選項 =>7 總購買金額 = 1470
** 採購清單列印中 (List.data) ** ** 列印完畢 (List.data) **
G:\Examples\chap9\PM9_1>type List.data 【type顯示檔案內容命令】 == 春嬌超商 購物清單 歡迎再度光臨 == 品名 單價 數量 小計 ----------------------------------------------------- 可口餅乾 20 24 480 御便當 50 15 750 頻果西打 30 8 240 總購買金額 = 1470 元整 |
(B)製作技巧提示:
圖 6-5 PM6_1 程式架構
吾人僅修改 Ex5_4.java 範例即可,原來購物清單是由螢幕顯示,將轉換到檔案輸出即可,虛擬碼提示如下:
/* 原 Ex5_4.java 程式內容 */ …. 宣告產生檔案輸出物件: String file = "List.data"; BufferedWriter data = new BufferedWriter(new FileWriter(file)); ….. 將物件陣列內容輸出到檔案內: data.write("== 春嬌超商 購物清單 歡迎再度光臨 ==\n"); data.write("品名\t\t單價 \t數量\t 小計\n"); data.write("------------------------------------\n"); for (int i=0; i<k; i++) { data.write(cust[i].name + "\t"); data.write(cust[i].price + "\t"); data.write(cust[i].pice + "\t"); data.write(cust[i].sum + "\n"); } data.write("總購買金額 = "+total+" 元整"); data.close(); /* 原 Ex5_4.java 程式內容 */ ….. |
6-4 紀錄檔案的輸入/輸出運用
6-4-1 記錄檔案輸出格式
讀取紀錄檔案大多是每次讀取一筆資料,即是每次讀取檔案內的一行資料,而不論每行包含多少屬性資料。各個屬性都有自己的資料型態,因此讀取時,只好將該筆資料可為一個字串(String)。圖 6-4 是讀取紀錄檔案的基本運作模式。每次讀取一筆資料並以字串格式儲存於 inData 變數內,亦可直接輸出到螢幕上。(如何轉換成陣列變數資料,下一個範例再說明,Ex6_2_1.java)
圖 6-4 紀錄檔案整筆輸入,並整筆輸出螢幕顯示
6-4-2 範例研討:建立員工薪資資料
(A)程式功能:Ex6_2.java
擴充 Ex6_1.java 程式功能。請幫志明電器製造公司建立一套人事管理系統,該系統允許輸入員工資料,並儲存於資料檔案內(Human.data)。當輸入完畢之後,再由檔案內讀出並顯示螢幕上,觀察資料是否建立正確。假設登錄員工資料包含有:員工代號(int)、姓名(String)、工作部門(String)、底薪(int)、職務加級(int);期望操作介面,以及檔案輸出結果如下:
G:\Examples\chap9\Ex6_2>java Ex6_2 是否繼續輸入員工資料 (yes/no) =>yes ***** 輸入員工資料 ***** 輸入員工姓名 =>張志明 輸入所屬部門 =>製造課 輸入員工代號 =>71209 輸入員工底薪 =>40000 輸入薪資加級 =>15000 是否繼續輸入員工資料 (yes/no) =>yes …… …… 是否繼續輸入員工資料 (yes/no) =>no ** 將資料輸出到 Human.dada 檔案內 ** ***** 輸出完畢 ****
== 由 Human.data 讀取並顯示 == 代號 姓名 部門 底薪 加級 71209 張志明 製造課 40000 15000 71210 羅大仙 製造課 43000 16800 71214 陳名郎 生管課 28000 12000 71219 蔡中心 倉管課 32000 17000 71242 劉新明 行銷課 28000 15000 == Human.data 輸入完畢 == |
(B)製作技巧研討:
本系統包含檔案(Human.data)輸出與輸入處理,其運作情形如圖 6-5 所示。也針對檔案輸出與輸入,分別產生下列兩個
物件,及其方法如下所示:
檔案名稱 |
String file = “Human.data”; |
||
輸出物件 |
BufferedWriter data = new BufferedWriter(new FileWriter(file)); |
||
寫入方法 |
data.write() |
||
關閉方法 |
dada.close() |
||
輸入物件 |
BufferedReader data_R = new BufferedReader(new FileReader(fileID)); |
||
讀取方法 |
data_R.read() |
||
關閉方法 |
data_R.cloas() |
圖 6-5 範例 Ex6_2 程式架構
Ex6_2 程式運作如下:程式開始時宣告產生鍵盤(標示 (1))與輸出檔案物件(標示 (2)),以及一只儲存資料的物件陣列,接著利用 while 迴圈連續讀取多筆資料,系統也隨時存入物件陣列內。操作者輸入完畢之後後,則將物件陣列內容,一筆接一筆寫入檔案(data.write(),標示 (2))。輸出完畢後,系統再由檔案讀出(data_R.read(),標示 (3)),也一筆接一筆顯示到螢幕上(標示 (4))。
(C)程式範例:
圖 6-8 Ex6_2 程式架構
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
//Ex6_2.java /* 擴充Ex6_1程式功能,將輸出的結果寫入檔案 */
import java.util.Scanner; import java.io.*; class Employee { /* 物件陣列的類別宣告 */ int ID; // 員工代號 String name; // 員工姓名 String depart; // 所屬部門 int payment; // 底薪 int duty; // 職務加級 }
public class Ex6_2 { public static void main(String args[]) throws IOException { Scanner keyin = new Scanner(System.in); Employee[] worker = new Employee[20];
/* 宣告輸出檔案物件 */ String file = "Human.data"; BufferedWriter data = new BufferedWriter(new FileWriter(file)); int k=0; String sel;
/* 讀入資料並存入物件陣列內 */ System.out.printf("是否繼續輸入員工資料 (yes/no) =>"); sel = keyin.nextLine(); while(sel.equals("yes") && (k <20)) { worker[k] = new Employee(); System.out.printf("***** 輸入員工資料 *****\n"); System.out.printf("輸入員工姓名 =>"); worker[k].name = keyin.nextLine(); System.out.printf("輸入所屬部門 =>"); worker[k].depart = keyin.nextLine(); System.out.printf("輸入員工代號 =>"); worker[k].ID = keyin.nextInt(); System.out.printf("輸入員工底薪 =>"); worker[k].payment = keyin.nextInt(); System.out.printf("輸入薪資加級 =>"); worker[k].duty = keyin.nextInt(); keyin.nextLine(); //清除鍵盤緩衝器 System.out.printf("是否繼續輸入員工資料 (yes/no) =>"); sel = keyin.nextLine(); k = k+1; }
/* 將物件陣列內容寫入檔案內 */ System.out.printf("** 將資料輸出到 Human.dada 檔案內 **\n"); for (int i=0; i<k; i++) { data.write(worker[i].ID + "\t"); data.write(worker[i].name + "\t"); data.write(worker[i].depart + "\t"); data.write(worker[i].payment + "\t"); data.write(worker[i].duty + "\n"); } data.close(); System.out.printf("***** 輸出完畢 ****\n");
/* 檔案輸出程式, 每次讀取一筆資料 */ System.out.printf("\n== 由 Human.data 讀取並顯示 ==\n"); String inData; File fileID = new File(file); //開啟 Human.data 檔案 if (fileID.exists()) { BufferedReader data_R = new BufferedReader(new FileReader(fileID)); System.out.print("代號\t姓名\t部門\t底薪\t加級\n"); while ((inData=data_R.readLine()) != null) System.out.printf("%s\n", inData); data_R.close(); } else System.out.printf("%s 檔案讀取錯誤\n", file); System.out.printf("== Human.data 輸入完畢 ==\n"); } } |
(D)程式重點說明:
G:\Examples>copy con: Human.data ^Z 複製了 1 個檔案。 |
6-4-3 自我挑戰:列印員工薪資表
(A)程式功能:PM6_2.java、Employee.class
志明電器公司已建立完成員工薪資管理系統(Ex6_2.java),該系統允許管理者輸入員工薪資資料,並可除儲存於 Human.data 檔案內。請編寫一套程式可供列印公司所有員工的薪資表,員工資料直接由 Human.data 檔案讀取。薪資表包含員工代號、姓名、服務部門,薪資總額(= 底薪 + 職務加級)、預扣稅額(= 薪資總額 * 0.1)與應領薪資(薪資總額 – 預扣稅額);期望操作如下:
D:\Java2_book\chap6\PM6_2>javac PM6_2.java
D:\Java2_book\chap6\PM6_2>dir/b Employee.class Human.data PM6_2.class
D:\Java2_book\chap6\PM6_2>java PM6_2 == 志明電器公司 員工薪資表 == 員工資料 薪資總額 預扣稅額 應領薪資 張志明(71209 製造課) 55000 5500 49500 羅大仙(71210 製造課) 59800 5980 53820 陳名郎(71214 生管課) 40000 4000 36000 蔡中心(71219 倉管課) 49000 4900 44100 劉新明(71242 行銷課) 43000 4300 38700
薪資總額 = 246800 元整 總稅額 = 24680 元整 總應額 = 222120 元整 |
(B)製作技巧研討:
本範例最大的特點是,每筆資料由檔案讀入後,如何儲存於物件陣列內,處理方式如圖 6-6 所示。首先系統利用 readLine() 方法讀入整筆資料後儲存於 inData 變數內,該資料還是屬於字串格式(String)。接著將 inData 導入 Scanner 類別,宣告其物件(data_R),其中必須設定字串資料之中各個欄位的『分界符號』(Demiliter),再利用 Scanner 物件方法,分別讀取各欄位資料再寫入陣列物件的變數成員內。相關之物件及其方法如下:
範例: |
說明: |
inData=data.readLine() |
由檔案讀取一筆資料。 |
Scanner s = new Scanner(inData).useDelimiter("\t"); |
宣告成 Scanner 物件並設定分界符號(\t),物件名稱為 s。 |
worker[k].ID = s.nextInt(); |
讀取一整數,再存入陣列物件的變數成員內。 |
圖 6-6 紀錄檔案讀入,每筆儲存於物件陣列內
(C)程式片段:
圖 6-10 PM6_2 程式架構
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
//PM6_2.java, Human.data 檔案需存在 /* Employee.class 需存在於同目錄下 */ import java.io.*; import java.util.Scanner; public class PM6_2 { public static void main(String args[]) throws IOException { Employee[] worker = new Employee[20]; String file = "Human.data"; String inData; int k=0; File fileID = new File(file); if (fileID.exists()) {
/* 由 Humam.data 讀取員工資料並存入 worker[] 陣列 */ BufferedReader data = new BufferedReader(new FileReader(fileID)); while ((inData=data.readLine()) != null) { Scanner s = new Scanner(inData).useDelimiter("\t"); worker[k] = new Employee(); worker[k].ID = s.nextInt(); worker[k].name = s.next(); worker[k].depart = s.next(); worker[k].payment = s.nextInt(); worker[k].duty = s.nextInt(); k = k +1; } data.close();
/* 計算並列印薪資表 */ System.out.printf("== 志明電器公司 員工薪資表 ==\n"); System.out.print("員工資料\t\t薪資總額\t預扣稅\t應領薪資\n"); …… …… else System.out.printf("%s 檔案不存在\n", file); } } |
(D)程式重點分析:
6-5 專題製作
6-5-1 範例研討:建立人事管理資訊系統
(A)程式功能:Ex6_3.java、Personal.java
『展鵬網路行銷公司』希望建立一個電子化管理系統,其中包含若干個子系統,各子系統所使用的員工資料都能夠統一處理,才不至於發生各系統之間不一致的問題。請您幫該公司規劃員工資料的屬性,並建立『人事資料管理系統』(Ex6_3.java)可讓管理人員『新增』、『修改』與『刪除』員工資料,爾後其他子系統也可引用該資料(Human.data)。目前預估員工資料包含有:員工代號、姓名、服務部門、性別、出生、底薪、職務加級等屬性,並由獨立檔案製作而成(Persional.java),經過編譯後產生 Persional.class。至於員工資料請以 Human.data 檔案名稱儲存。期望操作介面與執行結果如下:
D:\Java2_book\chap6\Ex6_3>java Ex6_3 Human.data 檔案不存在, 請先建立它 按<enter>鍵離開 => |
D:\Java2_book\chap6\Ex6_3>java Ex6_3 === 人事資料管理系統 === (1) 顯示所有資料 (2) 增加員工資料 (3) 修改員工資料 (4) 刪除員工資料 (5) 儲 存 資 料 (6) 離 開 系 統 請選擇工作項目 => |
請選擇工作項目 => 1 = 列印所有員工資料 == 代號 姓名 部門 性別 出生 底薪 加級 101 王力宏 會計課 男 63/12/5 80000 40000 102 張惠妹 業務課 女 64/3/12 90000 70000 103 蔡依玲 製造課 女 67/3/15 80000 60000 |
請選擇工作項目 => 2 請輸入員工編號 =>7106 請輸入姓名 =>劉有得 請輸入服務部門 =>資訊部 請輸入性別 (男/女) =>男 請輸入生日 (西元/月/日) =>71/09/12 請輸入底薪 =>54000 請輸入職務加級 =>11000 |
請選擇工作項目 => 3 請輸入欲修改員工的代號 =>7105 請輸入 張有德 姓名 =>張有得 請輸入 資訊部 服務部門 =>製造部 請輸入性別 男 (男/女) =>男 請輸入生日 75/09/23 (年/月/日) =>76/09/23 請輸入 60000 底薪 =>50000 請輸入 20000 職務加級 =>20000 |
請選擇工作項目 => 4 請輸入欲刪除員工的代號 =>7105 7105 資料已刪除 !! |
請選擇工作項目 => 5 ** 將儲存檔案 (Human.dada) ** ***** 儲存完畢 **** |
(B)製作技巧研討:
吾人將製作本系統的重點歸類成下列重點: (如圖 6-7 所示)
圖 6-11 人事資料管理系統架構
(C)程式範例:(執行前,須建立 Human.data 檔案)
圖 6_12 Ex6_3 程式架構
01 02 03 04 05 06 07 08 09 10 11 12 |
//Personal.java
class Personal { int ID; // 員工代號 String name; // 員工姓名 String depart; // 服務部門 String sex; // 性 別 String birth; // 出生日期 int payment; // 底 薪 int duty; // 職務加級 } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
//Ex6_3.java /* 請建立一套人事資料管理系統,可讓管理人員新增、修改、刪除員工資料 */
import java.io.*; import java.util.Scanner; public class Ex6_3 { static Personal[] emp; // 員工資料的物件陣列 static int k; // 紀錄儲存筆數 static Scanner keyin; // 鍵盤輸入物件
public static void main(String args[]) throws IOException { keyin = new Scanner(System.in);
/* 讀取 Human.data 檔案資料, 再存入 emp 物件陣列中 */ emp = new Personal[50]; k=0; // 讀取資料的筆數 String inData; String file_R = "Human.data"; File fileID = new File(file_R); // 產生輸入檔案物件 if (fileID.exists()) { BufferedReader data = new BufferedReader(new FileReader(fileID)); while ((inData=data.readLine()) != null) { Scanner s = new Scanner(inData).useDelimiter("\t"); emp[k] = new Personal(); emp[k].ID = s.nextInt(); emp[k].name = s.next(); emp[k].depart = s.next(); emp[k].sex = s.next(); emp[k].birth = s.next(); emp[k].payment = s.nextInt(); emp[k].duty = s.nextInt(); k = k +1; } data.close(); } else { System.out.printf("%s 檔案不存在, 請先建立它\n", file_R); System.out.printf("按任何鍵離開 =>"); keyin.nextLine(); System.exit(1); } mainMenu(); int select = keyin.nextInt(); while (select !=6) { switch (select) { case 1: /* 顯示員工資料 */ disp_data(); break; case 2: /* 增加員工資料 */ add_data(); break; case 3: /* 修改員工資料 */ modify_data(); break; case 4: /* 刪除資料 */ delete_data(); break; case 5: /* 儲存資料 */ save_data(); break; default: System.out.printf("錯誤輸入, 請重新選擇 !!\n"); } mainMenu(); select = keyin.nextInt(); } } public static void mainMenu() { System.out.printf("\n=== 人事資料管理系統 ===\n"); System.out.printf("(1) 顯示所有資料\t"); System.out.printf("(2) 增加員工資料\t"); System.out.printf("(3) 修改員工資料\n"); System.out.printf("(4) 刪除員工資料\t"); System.out.printf("(5) 儲 存 資 料\t"); System.out.printf("(6) 離 開 系 統\n"); System.out.printf("請選擇工作項目 => "); } public static void disp_data() { System.out.printf("== 列印所有員工資料 ==\n"); System.out.printf("代號\t姓名\t部門\t性別\t出生\t底薪\t加級\n"); for (int i=0; i<k; i++) { System.out.printf("%d\t", emp[i].ID); System.out.printf("%s\t", emp[i].name); System.out.printf("%s\t", emp[i].depart); System.out.printf("%s\t", emp[i].sex); System.out.printf("%s\t", emp[i].birth); System.out.printf("%d\t", emp[i].payment); System.out.printf("%d\n", emp[i].duty); } } public static void add_data() throws IOException { emp[k] = new Personal(); System.out.printf("請輸入員工編號 =>"); emp[k].ID = keyin.nextInt(); keyin.nextLine(); //清除鍵盤緩衝器 System.out.printf("請輸入姓名 =>"); emp[k].name = keyin.nextLine(); System.out.printf("請輸入服務部門 =>"); emp[k].depart = keyin.nextLine(); System.out.printf("請輸入性別 (男/女) =>"); emp[k].sex = keyin.nextLine(); System.out.printf("請輸入生日 (年/月/日) =>"); emp[k].birth = keyin.nextLine(); System.out.printf("請輸入底薪 =>"); emp[k].payment = keyin.nextInt(); System.out.printf("請輸入職務加級 =>"); emp[k].duty = keyin.nextInt(); k = k+1; } public static void modify_data() throws IOException { System.out.printf("請輸入欲修改員工的代號 =>"); int num = keyin.nextInt(); keyin.nextLine(); //清除鍵盤緩衝器 int flag = 0; int i = 0; while(i < k) { if (emp[i].ID == num) { flag = 1; break; } i = i + 1; } if (flag == 0) { System.out.printf("test here 5\n"); System.out.printf("沒有 %d 資料, 拒絕處理 !!\n", num); return; } System.out.printf("請輸入 %s 姓名 =>", emp[i].name); emp[i].name = keyin.nextLine(); System.out.printf("請輸入 %s 服務部門 =>", emp[i].depart); emp[i].depart = keyin.nextLine(); System.out.printf("請輸入性別 %s (男/女) =>", emp[i].sex); emp[i].sex = keyin.nextLine(); System.out.printf("請輸入生日 %s (年/月/日) =>", emp[i].birth); emp[i].birth = keyin.nextLine(); System.out.printf("請輸入 %d 底薪 =>", emp[i].payment); emp[i].payment = keyin.nextInt(); System.out.printf("請輸入 %d 職務加級 =>", emp[i].duty); emp[i].duty = keyin.nextInt(); } public static void delete_data() throws IOException { System.out.printf("請輸入欲刪除員工的代號 =>"); int num = keyin.nextInt(); int flag = 0, m = 0; while(m < k) { if (emp[m].ID == num){ flag = 1; break; } m = m + 1; } if (flag == 0){ System.out.printf("沒有 %d 資料, 拒絕處理 !!\n", num); return; } for(int i=m; i<k; i++) emp[i]=emp[i+1]; k = k-1; System.out.printf("%d 資料已刪除 !!\n", num); } public static void save_data() throws IOException { String file = "Human.data"; BufferedWriter outData = new BufferedWriter(new FileWriter(file)); System.out.printf("** 將儲存檔案 (Human.dada) **\n"); for (int i=0; i<k; i++) { outData.write(emp[i].ID + "\t"); outData.write(emp[i].name + "\t"); outData.write(emp[i].depart + "\t"); outData.write(emp[i].sex + "\t"); outData.write(emp[i].birth + "\t"); outData.write(emp[i].payment + "\t"); outData.write(emp[i].duty + "\n"); } outData.close(); System.out.printf("***** 儲存完畢 ****\n"); } } |
(D)程式重點分析:
6-5-2 自我挑戰:超商商品管理系統
(A)程式功能:PM6_3.java、Element.java
請幫『春嬌生鮮超市』建立一套商品登錄系統。該系統功能有『顯示所有資料』、『增加商品資料』、以及『儲存資料』。庫存資料儲存於 storage.data 檔案內。假設描述商品屬性(Element.java)為:商品編號(String no)、商品名稱(String name)、單價(int price)、單位(Sting unit)、庫存量(int stock)與製造商(String maker)。期望操作介面與結果如下:
D:\Java2_book\chap6\PM6_3>java PM6_3 storage.data 檔案不存在, 請先建立它 按 <Enter> 鍵離開 => |
D:\Java2_book\chap6\PM6_3>java PM6_3
== 春嬌超市 商品管理系統 == (1) 顯示所有資料 (2) 增加商品資料 (3) 修改商品資料 (4) 儲 存 資 料 (5) 離 開 系 統 請選擇工作項目 => |
D:\Java2_book\chap6\PM6_3>java PM6_3
== 春嬌超市 商品管理系統 == (1) 顯示所有資料 (2) 增加商品資料 (3) 修改商品資料 (4) 儲 存 資 料 (5) 離 開 系 統 請選擇工作項目 => |
請選擇工作項目 => 1 == 列印所有商品資料 == 代號 品名 單價 單位 庫存量 製造商 A1001 黑松汽水 20 個 210 黑松公司 A1002 可口奶滋 50 個 310 統一食品 |
請選擇工作項目 => 2 請輸入商品編號 =>1005 請輸入商品名稱 =>台灣啤酒 請輸入單價 =>60 請輸入單位 (個/箱/公斤) =>個 請輸入安全庫存量 =>50 請輸入製造商 =>台灣菸酒公司 |
請選擇工作項目 => 3 請輸入欲修改的商品編碼 =>A1005 [台灣啤酒]請輸入商品名稱 =>金門高粱 [60]請輸入單價 =>500 [個]請輸入單位 (個/箱/公斤) =>個 [50]請輸入庫存量 =>30 [台灣菸酒公司]請輸入製造商 =>金門酒廠 |
請選擇工作項目 => 4 ** 將儲存檔案 (storage.data) ** ***** 儲存完畢 **** |
(B)製作技巧提示:
為了方便製作,吾人可將此系統劃分為若干個子系統(方法或函數)來分別實現,如圖 6-8 所示;虛擬碼提示如下:
圖 6-8 超商商品管理系統架構
宣告商品類別(class Element { …}); 宣告主類別範圍(class PM9_2){ 宣告商品物件陣列(static Element[] art); 宣告紀錄資料筆數的變數(static int number); 宣告庫存檔案的變數(static String file); 宣告鍵盤輸入物件(static BufferedReader keyin); 宣告主方法範圍(main()){ 產生物件陣列範圍(art = new Element[50]); 設定類別變數內容(number=0、file=”storage.data); 呼叫執行讀取檔案資料方法(read_data()); 呼叫主功能選單(mainMenu())並讀取功能選項(select); while (select != 4) { switch(select) { case 1: disp_data() /* 顯示所有資料 */ case 2: add_data() /* 增加商品資料 */ case 3: modify_data() /* 修改商品資料 */ case 4: save_data() /* 儲存資料 */ } 呼叫主功能選單(mainMenu())並讀取功能選項(select); } } // 主方法結束 /* 主工作項目選單 */ 宣告主功能表選單方法(mainMenu() { ….}); 宣告檔案讀取方法(read_data()); /* 將 stroage.data 檔案讀入並存入 art[] 陣列 */ 宣告顯示所有資料方法(disp_data()); 宣告增加商品資料方法(add_data()); 宣告儲存商品資料方法(save_data()); /* 將 art[] 陣列內容輸出至 storage.data 檔案 */ } // 主類別結束 |
(C) 程式片段提示
圖 6-15 PM6_3 程式架構
01 02 03 04 05 06 07 08 09 10 11 12 |
//Element.java
class Element { String ID; // 商品編號 String name; // 商品名稱 int price; // 單價 String unit; // 單位 int stock; // 庫存數量 String maker; // 製造商 } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
//PM6_3.java /* 請建立一套商品登錄系統,功能有:顯示所有資料、增加商品資料、儲存資料; * 資料儲存於storage.data檔案內 */
/* Element.class 須於同目錄下 */ import java.io.*; import java.util.Scanner; public class PM6_3 { static Element[] art; // 商品資料的物件陣列 static int number; // 紀錄儲存筆數 static Scanner keyin; // 鍵盤輸入物件 static String file_R; // 庫存檔案
public static void main(String args[]) throws IOException { keyin = new Scanner(System.in);
art = new Element[50]; number=0; // 儲存資料的筆數 file_R = "storage.data"; read_data();
mainMenu(); int select = keyin.nextInt(); keyin.nextLine(); while (select !=5) { switch (select) { case 1: /* 顯示所有資料 */ disp_data(); break; case 2: /* 增加商品資料 */ add_data(); break; case 3: /* 修改商品資料 */ modify_data(); break; case 4: /* 儲存資料 */ save_data(); break; default: System.out.printf("錯誤輸入, 請重新選擇 !!\n"); } mainMenu(); select = keyin.nextInt(); keyin.nextLine(); } } /* 主工作項目選單 */ public static void mainMenu() { System.out.printf("\n== 春嬌超市 商品管理系統 ==\n"); ….. ….
}
/* 將 stroage.data 檔案輸入至系統 */ public static void read_data() throws IOException { File fileID = new File(file_R); // 產生輸入檔案物件 String inData; if (fileID.exists()) { BufferedReader data = new BufferedReader(new FileReader(fileID)); while ((inData=data.readLine()) != null) { Scanner s = new Scanner(inData).useDelimiter("\t"); art[number] = new Element(); art[number].ID = s.next(); art[number].name = s.next(); art[number].price = s.nextInt(); art[number].unit = s.next(); art[number].stock = s.nextInt(); art[number].maker = s.next(); number = number +1; } data.close(); } else { System.out.printf("%s 檔案不存在, 請先建立它 \n", file_R); System.out.printf("按 <Enter> 鍵離開 =>"); keyin.nextLine(); System.exit(1); } }
/* 顯示所有資料 */ public static void disp_data() { System.out.printf("== 列印所有商品資料 ==\n"); System.out.printf("代號\t品名\t\t單價\t單位\t安全庫存量\t製造商\n"); for (int i=0; i<number; i++) { System.out.printf("%s\t", art[i].ID); System.out.printf("%4s\t", art[i].name); System.out.printf("%d\t", art[i].price); System.out.printf("%s\t", art[i].unit); System.out.printf("%d\t\t", art[i].stock); System.out.printf("%s\n", art[i].maker); } }
/* 增加商品資料 */ public static void add_data(){ int k=number; art[k] = new Element(); System.out.printf("請輸入商品編號 =>"); art[k].ID = keyin.nextLine(); System.out.printf("請輸入商品名稱 =>"); art[k].name = keyin.nextLine(); System.out.printf("請輸入單價 =>"); art[k].price = keyin.nextInt(); keyin.nextLine(); System.out.printf("請輸入單位 (個/箱/公斤) =>"); art[k].unit = keyin.nextLine(); System.out.printf("請輸入庫存量 =>"); art[k].stock = keyin.nextInt(); keyin.nextLine(); System.out.printf("請輸入製造商 =>"); art[k].maker = keyin.nextLine(); number = number+1; }
/* 修改商品資料 */ public static void modify_data(){ System.out.printf("請輸入欲修改的商品編碼 =>"); String num = keyin.nextLine(); int flag = 0, test; int i = 0; while(i < number) { test = art[i].ID.compareTo(num); if (test == 0) { flag = 1; break; } i = i + 1; } if (flag == 0) { System.out.printf("沒有 %s 資料, 拒絕處理 !!\n", num); return; } System.out.printf("[%s]請輸入商品名稱 =>", art[i].name); art[i].name = keyin.nextLine(); System.out.printf("[%d]請輸入單價 =>", art[i].price); art[i].price = keyin.nextInt(); keyin.nextLine(); System.out.printf("[%s]請輸入單位 (個/箱/公斤) =>", art[i].unit); art[i].unit = keyin.nextLine(); System.out.printf("[%d]請輸入庫存量 =>", art[i].stock); art[i].stock = keyin.nextInt(); keyin.nextLine(); System.out.printf("[%s]請輸入製造商 =>", art[i].maker); art[i].maker = keyin.nextLine(); }
/* 儲存商品資料至 storage.data */ public static void save_data() throws IOException { BufferedWriter outData = new BufferedWriter(new FileWriter(file_R)); System.out.printf("** 將儲存檔案 (storage.data) **\n"); for (int i=0; i<number; i++) { outData.write(art[i].ID + "\t"); outData.write(art[i].name + "\t"); outData.write(art[i].price + "\t"); outData.write(art[i].unit + "\t"); outData.write(art[i].stock + "\t"); outData.write(art[i].maker + "\n"); } outData.close(); System.out.printf("***** 儲存完畢 ****\n"); } } |
6-5-3 自我挑戰:倉儲管理系統
(A)程式功能:PM6_4
(擴充 PM6_3.java 功能)請幫『春嬌超商連鎖店』建立一套『倉儲管理系統』,可供隨時登錄各連鎖店進出貨量。該系統功能有『顯示所有資料』、『增加商品資料』、『出貨登錄』、『進貨登錄』、以及『儲存資料』。庫存資料儲存於 storage.data 檔案內。當點選『出貨』或『進貨』功能時,系統會將目前所建立的商品資料顯示於螢幕上,管理者點選產品再輸入數量即可。假設描述商品屬性(article.class)為:商品編號(String no)、商品名稱(String name)、單價(int price)、單位(Sting unit)、庫存量(int stock)與製造商(String maker)。
D:\Java2_book\chap6\PM6_4>javac PM6_4.java
D:\Java2_book\chap6\PM6_4>java PM6_4
== 春嬌超市 商品管理系統 == (1) 顯示所有資料 (2) 增加商品資料 (3) 修改商品資料 (4) 進貨資料登錄 (5) 出貨資料登錄 (6) 儲 存 資 料 (7) 離 開 系 統 請選擇工作項目 => |
請選擇工作項目 => 4 === 請點選 (進出貨) 商品 == (1) 黑松汽水 260 (2) 可口奶滋 410 (3) 可口可樂 500 (4) 台灣啤酒 200 (5) 滿漢大餐 200 請輸入商品選項 =>4 進貨數量 =>50
= 春嬌超市 商品管理系統 == 1) 顯示所有資料 (2) 增加商品資料 (3) 修改商品資料 4) 進貨資料登錄 (5) 出貨資料登錄 (6) 儲 存 資 料 7) 離 開 系 統 請選擇工作項目 => 1 = 列印所有商品資料 == 代號 品名 單價 單位 安全庫存量 製造商 1001 黑松汽水 20 個 260 黑松公司 1002 可口奶滋 50 個 410 統一食品 1003 可口可樂 15 個 500 英商太古 1004 台灣啤酒 60 個 250 台灣菸酒 1005 滿漢大餐 50 個 200 統一食品 |
請選擇工作項目 => 5 === 請點選 (進出貨) 商品 == (1) 黑松汽水 260 (2) 可口奶滋 410 (3) 可口可樂 500 (4) 台灣啤酒 250 (5) 滿漢大餐 200 請輸入商品選項 =>3 出貨數量 =>200
== 春嬌超市 商品管理系統 == (1) 顯示所有資料 (2) 增加商品資料 (3) 修改商品資料 (4) 進貨資料登錄 (5) 出貨資料登錄 (6) 儲 存 資 料 (7) 離 開 系 統 請選擇工作項目 => 1 == 列印所有商品資料 == 代號 品名 單價 單位 安全庫存量 製造商 A1001 黑松汽水 20 個 260 黑松公司 A1002 可口奶滋 50 個 410 統一食品 A1003 可口可樂 15 個 300 英商太古 A1004 台灣啤酒 60 個 250 台灣菸酒 A1005 滿漢大餐 50 個 200 統一食品 |
請選擇工作項目 => 6 ** 將儲存檔案 (storage.data) ** ***** 儲存完畢 **** |
(B)製作技巧提示:
圖 6-16 PM6_4 程式架構
本系統大致上與 PM6_3.java 相似,僅增加了『進貨登錄』與『出貨登錄』功能選項。當執行這兩項功能時,系統必須將目前已登錄產品與數量,顯示於螢幕上;操作者點選後,再輸入進出貨數量。因此,必須另製作一只顯示產品名稱與數量,並可選擇輸入的子程式(list_art()),兩功能子程式(enter_date() 與 out_data())分別呼叫它,再傳回正確的產品選項。這三個子程式提示如下:
/* 進貨登錄子程式 */ public static void enter_data(){ int num = list_art(); if (num == 999) { return; } System.out.printf("進貨數量 =>"); int enter = keyin.nextInt(); keyin.nextLine(); art[num].stock = art[num].stock + enter; } /* 出貨登錄子程式 */ public static void out_data(){ int num = list_art(); if (num == 999) { return; } System.out.printf("出貨數量 =>"); int outer = keyin.nextInt(); keyin.nextLine(); art[num].stock = art[num].stock - outer; }
/* 顯示商品清單及選擇商品子程式 */ public static int list_art() { System.out.printf(" === 請點選 (進出貨) 商品 ==\n"); for (int i=0; i<number; i++) { System.out.printf("(%d) %s %d ", i+1, art[i].name, art[i].stock); if ((i+1) % 4 == 0) System.out.printf("\n"); } System.out.printf("\n請輸入商品選項 =>"); int num = keyin.nextInt(); keyin.nextLine(); num = num -1; if ((num >= number) || (num < 0) ){ System.out.printf("錯誤輸入!! 按任何鍵回主選單\n"); keyin.readLine(); return 999; } return num; } |