檔案讀寫與例外處理 (File IO and Exception Handling)

Slides:



Advertisements
Similar presentations
第四章 类、对象和接口.
Advertisements

3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
四資二甲 第三週作業 物件導向程式設計.
C#程序设计案例教程 第3章 程 序 结 构.
程設一.
C#程序设计 10软件1、2班 王槐彬 计算机工程学院.
第二章 JAVA语言基础.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
C# 程式設計 第一部分 第1-4章 C# 程式設計 - 南華大學資管系.
程式設計實作.
第5章 异常处理 王德俊 上海交通大学继续教育学院.
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
C#程序设计 c# programming 泛型 C#程序设计课程组.
第八章 C#高级编程.
.NET 程式設計入門(使用 C#) 講師:鄧智鴻.
第二章 C# 基础知识.
第四章 在 C# 中实现 OOP 概念.
例外處理(Exception Handling)
Java基础 JavaSE异常.
南华大学计算机学院 软件工程系 QQ讨论群:
第十三章 文件和注册表操作.
Java 程式設計 講師:FrankLin.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第五章 继承、接口与范型.
第三章 C#面向对象初级编程 面向对象得程序设计越来越受到编程人员的喜爱。类和对象是面向对象程序设计中的重要概念。封装性、继承性和多态性是面向对象的特点,本章旨在全面说明C#编写面向对象程序设计的方法。
基于 C# 的 .NET Framework 程序设计
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
程式撰寫流程.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Java语言程序设计 第五部分 Java异常处理.
王豐緒 銘傳大學資訊工程學系 問題:JAVA 物件檔輸出入.
第三章 流程控制與例外處理 資訊教育研究室 製作 注意:本投影片僅供上課使用,非經同意,請勿散播或轉載。
辅导课程十三.
C#面向对象程序设计 $7 继承和多态性.
文件流. 文件流 文件流 Stream FileStream BufferedStream MemoryStream NetworkStream …… 所有流的抽象 Stream FileStream BufferedStream MemoryStream NetworkStream ……
視窗程式設計 (Windows Programming)
例外處理與 物件序列化(Exception Handling and Serialization of Objects)
9.1 程式偵錯 9.2 捕捉例外 9.3 自行拋出例外 9.4 自定例外類別 9.5 多執行緒
$16 进程和线程. $16 进程和线程 进程 进程 属性 ProcessName / Id MachineName / MainModule BasePriority StartTime / ExitTime TotalProcessorTime / UserProcessorTime PrivateMemorySize64.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
第 十二 章 C# 中的文件处理.
异常及处理.
第六章 属性、索引器、委托和事件.
P2P聊天工具.
類別與物件 I (Classes and Objects I)
4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: QQ:
第三章 C# 基础知识.
辅导课程八.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
一個基於Web Service的 洪氾預警系統
第7章 异常处理.
第二章 Java基本语法 讲师:复凡.
第3章 JavaScript基本语句.
第二章 Java语法基础.
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
Java程序设计 第17章 异常和断言.
JAVA 程式設計與資料結構 第三章 物件的設計.
檔案讀寫與例外處理 (File IO and Exception Handling)
第2章 Java语言基础.
C#快速導讀 流程控制.
判斷(選擇性敘述) if if else else if 條件運算子.
第二章 Java基本语法 讲师:复凡.
第6章 继承和多态 伍孝金
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
Presentation transcript:

檔案讀寫與例外處理 (File IO and Exception Handling) 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

加入文字檔 專案/加入新項目/文字檔/名稱/加入 鍵入資料 檔案/另存***為. . . 檢查儲存位置

串流(Stream)的觀念 StreamReader 輸入檔 Heap 記憶區 StreamWriter 輸出檔

FileDemo.Program (1/6) /* * 示範文字檔案之讀寫 * skj 4/20/2007 * * 假設欲讀入之資料檔格式如下: * 第一列為一個整數代表以下每列有多少個整數數據 * 欲寫出之資料檔格式與欲讀入之資料檔格式相似 * 測試: * 欲讀入之資料檔檔名為Test.dat * 欲寫出之資料檔檔名為Test.output

FileDemo.Program (2/6) * 欲讀入之資料檔內容為(數據之間以一個空白隔開) * 3 * 1 4 2 * 2 3 5 * 7 6 9 * 8 3 12 * 11 10 235 * * 寫出之資料檔內容相同, 但數據之間以TAB('\t')分開, 即 * 1 4 2 * 2 3 5 * 7 6 9 * 8 3 12 * 11 10 235

FileDemo.Program (3/6) * 注意如果執行偵錯版本, 所用資料檔要放在專案的bin\Debug * 檔案夾, * 如果不偵錯, 須放在bin\Release檔案夾, 否則檔案名要用完整 * 檔案路徑 */ using System; using System.IO; namespace FileDemo { class Program static void Main(string[] args)

FileDemo.Program (4/6) Console.Write("輸入欲讀入之資料檔名: "); string fileName = Console.ReadLine(); StreamReader input = new StreamReader(fileName); Console.Write("輸入欲寫出之資料檔名: "); fileName = Console.ReadLine(); StreamWriter output = new StreamWriter(fileName); string line; string[] head = new string[2]; // 讀入並寫出第一列 line = input.ReadLine(); int nDataPerLine = int.Parse(line); output.WriteLine(nDataPerLine);

FileDemo.Program (5/6) // 讀入並寫出後續數據 string[] dataString = new string[nDataPerLine]; int data; while (!input.EndOfStream) { line = input.ReadLine(); dataString = line.Split(' '); for ( int i = 0; i < nDataPerLine; ++i) data = int.Parse(dataString[i]); Console.Write(data + "\t"); output.Write(data + "\t"); }

FileDemo.Program (6/6) Console.WriteLine(); output.WriteLine(); } output.Close(); input.Close();

練習 產生一文字資料檔,在其中用星號*和空白製作圖案 撰寫程式讀取此一資料檔,並在螢幕印出其中圖案

範例問題 假設有一N_ROW列、N_COL欄的整數表格,寫一程式計算每列總和、每欄總和、及全部總和。以如下2列3欄表格為例(Case 1): 其每列總和為 9、18,每欄總和為8、11、8,全部總和為27。利用一個二維陣列儲存表格資料,兩個一維陣列分別儲存每列總和及每欄總和。 3 4 2 5 7 6

資料檔格式 2, 3 3, 4, 2 5, 7, 6 i.e., <nRow>, <nCol> <data[0,0]>, <data[0,1]>, . . ., <data[0,nCol]> . . . <data[nRow,0]>, <data[nRow,1]>, . . ., <data[nRow, nCol]>

TableDemo.Program片段 using System; using System.Diagnostics; namespace TableDemo { class Program static void Main(string[] args) Debug.Assert(TableTest.Case1_OK(), "Table test: Case 1 failed"); }

TableDemo.TableTest 片段 public static bool Case1_OK() { Table table = new Table("Test1.dat"); int[] rowSum = table.RowSum(); Debug.Assert(rowSum[0] == 9); Debug.Assert(rowSum[1] == 18); int[] colSum = table.ColSum(); Debug.Assert(colSum[0] == 8); Debug.Assert(colSum[1] == 11); Debug.Assert(colSum[2] == 8); Debug.Assert(table.TotalSum() == 27); return true; }

TableDemo.Table 片段(1/6) private int nRow; private int nCol; private int[,] data; public Table(string fileName) { StreamReader input = new StreamReader(fileName); string line; string[] head = new string[2]; line = input.ReadLine(); head = line.Split(','); nRow = int.Parse(head[0]); nCol = int.Parse(head[1]); data = new int[nRow, nCol];

TableDemo.Table 片段(2/6) int i; int j; for (i = 0; i < nRow; ++i) { string[] dataString = new string[nCol]; int i; int j; for (i = 0; i < nRow; ++i) { line = input.ReadLine(); dataString = line.Split(','); for (j = 0; j < nCol; ++j) data[i,j] = int.Parse(dataString[j]); }

TableDemo.Table 片段(3/6) public int[] RowSum() { int[] rowSum = new int[nRow]; for (int i = 0; i < nRow; ++i) rowSum[i] = 0; for (int j = 0; j < nCol; ++j) rowSum[i] += data[i, j]; } return rowSum;

TableDemo.Table 片段(4/6) public int[] ColSum() { int[] colSum = new int[nCol]; for (int j = 0; j < nCol; ++j) colSum[j] = 0; for (int i = 0; i < nRow; ++i) colSum[j] += data[i, j]; } return colSum;

TableDemo.Table 片段(5/6) public int TotalSum() { int totalSum = 0; for (int i = 0; i < nRow; ++i) for (int j = 0; j < nCol; ++j) totalSum += data[i, j]; } return totalSum;

練習 在類別Table中增加建構式public Table(int[,] data) ,以便由一個矩形陣列建立表格 在類別TableTest中增加public static bool Case2_OK() ,以測試上述建構式 修改主程式,進行測試

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

錯誤代碼應用例虛擬碼(1/3) readFile { openFile; determineSize; allocateMemory; readFileIntoMemory; closeFile; } *吳瑞千譯, W. D. Mitchell原著, JAVA 程式疑難排解, 麥格羅希爾, 2001, pp. 3-8 ~3-10.

錯誤代碼應用例虛擬碼(2/3) errorCodeType readFile { initialize errorCode = 0; openFile; if( fileIsOpen ) { determineSize; if( gotFileLength ) { allocateEnoughMemory; if( memoryAllocated ) { readFileIntoMemory; if( readFailed ) { errorCode = -1; handleError; } else { errorCode = -2; handleError; }

錯誤代碼應用例虛擬碼(3/3) } else { errorCode = -3; handleError; } closeFile; if( fileDidNotClose && errorCode == 0 ) { errorCode = -4; handleError; errorCode = -5; handleError; return errorCode;

Try-Catch 應用例虛擬碼(1/2) readFile { try { openFile; determineSize; allocateMemory; readFileIntoMemory; closeFile;

Try-Catch 應用例虛擬碼(2/2) } catch( fileDidNotOpen ) { handleError; // or throwException } catch( sizeNotDetermined ) { } catch( memoryAllocationFailed ) { } catch( couldNotReadFile ) { } catch( couldNotCloseFile ) { }

例外處理優點 分離正常與錯誤處理程式碼,易於了解及偵錯 例外物件包含所需清楚資訊,減輕記憶負擔,易於使用 易於繼承衍生例外物件, 減少所需重複程式碼

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

UsingTryCatch.Program (1/3) /* * 示範try...catch之使用 * 5/14/2007 */ using System; namespace UsingTryCatch { class Program static void Main(string[] args)

UsingTryCatch.Program (2/3) { Console.Write("輸入除數: "); int number = int.Parse(Console.ReadLine()); int result = 5 / number; } catch (Exception e) Console.WriteLine("發生例外"); Console.WriteLine("例外原因: " + "\n\n" + e.Message + "\n"); Console.WriteLine("擲出例外之方法的呼叫堆疊: " + "\n\n" + e.StackTrace + "\n");

UsingTryCatch.Program (3/3) Console.WriteLine("擲出例外之地點: " + "\n\n" + e.TargetSite + "\n"); Console.WriteLine( "擲出例外之程式物件來源: " + "\n\n" + e.Source + "\n"); Console.WriteLine("例外之相關細節: " + "\n\n" + e.ToString() + "\n"); }

UsingTryCatch2.Program (1/3) /* 捕捉不同例外 * 5/14/2007 */ using System; namespace UsingTryCatch2 { class Program static void Main(string[] args) bool success = false; do try

UsingTryCatch2.Program (2/3) Console.Write("輸入除數: "); int number = int.Parse(Console.ReadLine()); int result = 5 / number; Console.WriteLine("除結果為" + result); success = true; } catch (FormatException e) { Console.WriteLine("請輸入數值"); Console.WriteLine(e.Message); catch (DivideByZeroException e) Console.WriteLine("不可除以零");

UsingTryCatch2.Program (3/3) catch (Exception e) { Console.WriteLine("其他錯誤"); Console.WriteLine(e.Message); } finally if (!success) Console.WriteLine("再試一次"); } while (!success);

練習 參考FileDemo程式,寫一程式打開一不存在之資料檔,觀察會有何例外發生 修改程式catch此例外,印出訊息後結束程式執行

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

UserDefinedException.Program (1/5) /* * 示範使用者自訂例外之使用 * 5/22/2010 */ using System; namespace UserDefinedException { class Program static void Main(string[] args) int nStudents = 3;

UserDefinedException.Program (2/5) Student[] table = new Student[nStudents]; try { table[0] = new Student("B645330", 90); Console.WriteLine("table[0] = {0} : {1}", table[0].RegNo, table[0].Grade); table[1] = new Student("B645331", 102); //table[1] = new Student("B645331", 100); Console.WriteLine("table[1] = {0} : {1}", table[1].RegNo, table[1].Grade); table[2] = new Student("B645332", 55); Console.WriteLine("table[2] = {0} : {1}", table[2].RegNo, table[2].Grade); //Console.WriteLine("table[3] = {0} : {1}", // table[3].RegNo, table[3].Grade); }

UserDefinedException.Program (3/5) catch (GradeOutOfRangeException e) { Console.WriteLine(e); } catch (IndexOutOfRangeException e) Console.WriteLine(e.Message); catch (Exception e)

UserDefinedException.Program (4/5) class Student { private string regNo; private int grade; public Student(string regNo, int grade) { if (grade < 0 || grade > 100) throw new GradeOutOfRangeException( regNo, grade); this.regNo = regNo; this.grade = grade; } public string RegNo { get { return regNo; } public int Grade { get { return grade; }

UserDefinedException.Program (5/5) class GradeOutOfRangeException : ApplicationException { private string message; public GradeOutOfRangeException( string regNo, int grade) : base() message = "學生" + regNo + "之分數" + grade + "不在0與100之間"; } public override string ToString() return message;

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

例外類別階層 Exception ApplicationException SystemException ArithmeticException DivideByZeroException NotFiniteNumberException OverflowException FormatException InvalidCastException IndexOutOfRangeException NullReferenceException StackOverflowException IOException

練習 撰寫類別Square,模擬邊長為a的正方形。在以a為輸入參數之建構式中檢驗a是否為正,若否則throw一自訂之例外物件 撰寫此一自定之例外類別 撰寫測試程式,嘗試建立邊長為-1的正方形,並catch例外,輸出訊息後結束

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

NestedTryAndCatch.Program(1/7) /* * 示範巢狀try...catch敘述之使用 * 5/22/2010 */ using System; namespace NestedTryAndCatch { class Program static void Main(string[] args) int nStudents = 1; bool validNStudents = false;

NestedTryAndCatch.Program(2/7) do { Console.Write("輸入學生人數: "); try nStudents = int.Parse(Console.ReadLine()); if (nStudents > 0) validNStudents = true; } catch (FormatException e) Console.WriteLine(e.Message); catch (Exception e) } while (!validNStudents);

NestedTryAndCatch.Program(3/7) { Student[] table = new Student[nStudents]; for (int i = 0; i < nStudents; ++i) bool validGrades = false; do Console.WriteLine("輸入第" + (i + 1) + " 個學生學號及成績, 以一個空白分隔: "); string line; string[] data = new string[2]; line = Console.ReadLine(); data = line.Split(' ');

NestedTryAndCatch.Program(4/7) string regNo = data[0]; int grade = Convert.ToInt32(data[1]); table[i] = new Student(regNo, grade); Console.WriteLine( "table[" + i + "] = {0} : {1}", table[i].RegNo, table[i].Grade); validGrades = true; } catch (GradeOutOfRangeException e){ Console.WriteLine(e); catch (FormatException e) { Console.WriteLine(e.Message); } while (!validGrades);

NestedTryAndCatch.Program(5/7) catch (IndexOutOfRangeException e) { Console.WriteLine(e.Message); } catch (Exception e)

NestedTryAndCatch.Program(6/7) class Student { private string regNo; private int grade; public Student(string regNo, int grade) { if (grade < 0 || grade > 100) throw new GradeOutOfRangeException( regNo, grade); this.regNo = regNo; this.grade = grade; } public string RegNo { get { return regNo; } public int Grade { get { return grade; }

NestedTryAndCatch.Program(7/7) class GradeOutOfRangeException : ApplicationException { private string message; public GradeOutOfRangeException(string regNo, int grade) : base() message = "學生" + regNo + "之分數" + grade + "不在0與100之間"; } public override string ToString() return message;

練習 將NestedTryAndCatch程式改為由資料檔讀取資料,注意catch檔案不存在的例外狀況 測試一錯誤資料檔,使程式提早遇到End Of File的情況,觀察有何例外發生 修改程式,使能處理End Of File的情況

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

串流(Stream) 檔案 程式變數 位元組串流 Test.dat 程式變數 位元組串流 網路接口 (Socket)

程式執行時自動產生的串流物件 類別Console的三個相關資料成員 Console.In Console.Out Console.Error 連接至鍵盤,標準輸入串流物件 用於Console函式Read與ReadLine Console.Out 連接至螢幕,標準輸出串流物件 用於Console函式Write與WriteLine Console.Error 連接至螢幕,標準錯誤訊息輸出串流物件

命名空間System.IO

System.IO中的類別 StreamReader StreamWriter FileStream MemoryStream 自檔案輸入文字 StreamWriter 輸出文字至檔案 FileStream 輸入及輸出至檔案均可能 MemoryStream BufferedStream

綱要 簡易檔案讀寫 錯誤代碼 例外物件、try、catch、finally 自訂例外 例外類別的階層結構 巢狀try與catch 檔案類別 物件序列化

物件序列化(Serialization)與 去序列化(Deserialization) 利用BinaryFormatter,在Stream進行 序列化 將物件轉換為適當格式之資料,寫入檔案 去序列化 自檔案以適當格式讀出資料,重建物件

UsingSerialization.Program (1/8) /* * 以類別Student及GraduateStudent說明物件的序列化與 * 去序列化 * 5/22/2010 */ using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Diagnostics; namespace UsingSerialization { [Serializable] class Student private string regNo; private string name;

UsingSerialization.Program (2/8) public Student() { regNo = ""; name = ""; } public Student(string regNo, string name){ this.regNo = regNo; this.name = name; public string RegNO { get { return regNo; } public string Name { get { return name; }

UsingSerialization.Program (3/8) [Serializable] class GraduateStudent : Student { private string advisor; public GraduateStudent() : base() { advisor = ""; } public GraduateStudent( string regNo, string name, string advisor) : base(regNo, name) { this.advisor = advisor; public string Advisor { get { return advisor; }

UsingSerialization.Program (4/8) class Program { static void Main(string[] args) Student so1 = new Student( "B645331", "Thomas"); GraduateStudent so2 = new GraduateStudent( "F685329", "Richard", "Aaron"); BinaryFormatter formatter = new BinaryFormatter(); try { FileStream output = new FileStream("Test.dat", FileMode.Create, FileAccess.Write);

UsingSerialization.Program (5/8) formatter.Serialize(output, so1); formatter.Serialize(output, so2); output.Close(); } catch (SerializationException) { Console.WriteLine( "Error writting to file in output"); catch (IOException) "Can not create or close file for output"); try

UsingSerialization.Program (6/8) FileStream input = new FileStream("Test.dat", FileMode.Open, FileAccess.Read); try { while (true) Object obj = formatter.Deserialize(input); if ( obj.GetType() == so1.GetType()) Student si = (Student)obj;

UsingSerialization.Program (7/8) Console.WriteLine( si.RegNO + "\t" + si.Name ); } else if (obj.GetType() == so2.GetType()) { GraduateStudent si = (GraduateStudent)obj; Console.WriteLine( si.RegNO + "\t" + si.Name + "\t" + si.Advisor); else { throw new SerializationException();

UsingSerialization.Program (8/8) catch (SerializationException) { // close stream if no data left input.Close(); } catch (IOException) { Console.WriteLine( "Can not close file for input"); catch (FileNotFoundException) { "Can not open file in building intput");