java i o流异常问题_第四章 Java的I/O流和异常处理
Java.io包幾乎包含了所有操作輸入、輸出需要的類。所有這些流類代表了輸入源和輸出目標。? Java.io包中的流支持很多種格式,比如:基本類型、對象、本地化字符集等等。? 一個流可以理解為一個數(shù)據(jù)的序列。輸入流表示從一個源讀取數(shù)據(jù),輸出流表示向一個目標寫數(shù)據(jù)。? Java為I/O提供了強大的而靈活的支持,使其更廣泛地應用到文件傳輸和網(wǎng)絡編程中。
讀取控制臺輸入
Java的控制臺輸入由System.in完成。? 為了獲得一個綁定到控制臺的字符流,可以把System.in包裝在一個BufferedReader 對象中來創(chuàng)建一個字符流。? 下面是創(chuàng)建BufferedReader的基本語法:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader對象創(chuàng)建后,我們便可以使用read()方法從控制臺讀取一個字符,或者用readLine()方法讀取一個字符串
從控制臺讀取多字符輸入
從BufferedReader對象讀取一個字符要使用read()方法,它的語法如下:
int read( ) throws IOException
每次調用read()方法,它從輸入流讀取一個字符并把該字符作為整數(shù)值返回。 當流結束的時候返回-1。該方法拋出IOException。? 下面的程序示范了用read()方法從控制臺不斷讀取字符直到用戶輸入”q”
// 使用 BufferedReader 在控制臺讀取字符
import java.io.*;
public class BRRead {
public static void main(String args[]) throws IOException
{
char c;
// 使用 System.in 創(chuàng)建 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter characters, 'q' to quit.");
// 讀取字符
do {
c = (char) br.read();
System.out.println(c);
} while(c != 'q');
}
}
以上運行結果如下:
Enter characters, ‘q’ to quit.? 123abcq? 1? 2? 3? a? b? c? q
從控制臺讀取字符串
從標準輸入讀取一個字符串需要使用BufferedReader的readLine()方法。? 它的一般格式是:
String readLine( ) throws IOException
下面的程序讀取和顯示字符行直到你輸入了單詞”end”:
// 使用 BufferedReader 在控制臺讀取字符
import java.io.*;
public class BRReadLines {
public static void main(String args[]) throws IOException
{
// 使用 System.in 創(chuàng)建 BufferedReader
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String str;
System.out.println("Enter lines of text.");
System.out.println("Enter 'end' to quit.");
do {
str = br.readLine();
System.out.println(str);
} while(!str.equals("end"));
}
}
以上運行結果如下:
Enter lines of text.? Enter ‘end’ to quit.? This is line one? This is line one? This is line two? This is line two? end? end
JDK 5 后的版本我們也可以使用 Java Scanner 類來獲取控制臺的輸入
控制臺輸出
控制臺的輸出由 print( ) 和println( )完成。這些方法都由類PrintStream 定義,System.out是該類對象的一個引用。? PrintStream 繼承了OutputStream類,并且實現(xiàn)了方法write()。這樣,write()也可以用來往控制臺寫操作。
PrintStream 定義write()的最簡單格式如下所示:
void write(int byteval)
該方法將byteval的低八位字節(jié)寫到流中。
實例? 下面的例子用write()把字符”A”和緊跟著的換行符輸出到屏幕:
import java.io.*;
// 演示 System.out.write().
public class WriteDemo {
public static void main(String args[]) {
int b;
b = 'A';
System.out.write(b);
System.out.write('\n');
}
}
運行以上實例在輸出窗口輸出”A”字符:
A
注意:write()方法不經(jīng)常使用,因為print()和println()方法用起來更為方便。
讀寫文件
如前所述,一個流被定義為一個數(shù)據(jù)序列。輸入流用于從源讀取數(shù)據(jù),輸出流用于向目標寫數(shù)據(jù)。? 下圖是一個描述輸入流和輸出流的類層次圖:
下面將要討論的兩個重要的流是FileInputStream 和FileOutputStream:
FileInputStream
該流用于從文件讀取數(shù)據(jù),它的對象可以用關鍵字new來創(chuàng)建。? 有多種構造方法可用來創(chuàng)建對象。? 可以使用字符串類型的文件名來創(chuàng)建一個輸入流對象來讀取文件:
InputStream f = new FileInputStream(“C:/java/hello”);
也可以使用一個文件對象來創(chuàng)建一個輸入流對象來讀取文件。我們首先得使用File()方法來創(chuàng)建一個文件對象:
File f = new File(“C:/java/hello”);? InputStream f = new FileInputStream(f);
創(chuàng)建了InputStream對象,就可以使用下面的方法來讀取流或者進行其他的流操作:
public void close() throws IOException{}
關閉此文件輸入流并釋放與此流有關的所有系統(tǒng)資源。拋出IOException異常。
protected void finalize()throws IOException {}
這個方法清除與該文件的連接。確保在不再引用文件輸入流時調用其 close 方法。拋出IOException異常。
public int read(int r)throws IOException{}
這個方法從InputStream對象讀取指定字節(jié)的數(shù)據(jù)。返回為整數(shù)值。返回下一字節(jié)數(shù)據(jù),如果已經(jīng)到結尾則返回-1。
public int read(byte[] r) throws IOException{}
這個方法從輸入流讀取r.length長度的字節(jié)。返回讀取的字節(jié)數(shù)。如果是文件結尾則返回-1。
public int available() throws IOException{}
返回下一次對此輸入流調用的方法可以不受阻塞地從此輸入流讀取的字節(jié)數(shù)。返回一個整數(shù)值。
FileOutputStream
該類用來創(chuàng)建一個文件并向文件中寫數(shù)據(jù)。? 如果該流在打開文件進行輸出前,目標文件不存在,那么該流會創(chuàng)建該文件。? 有兩個構造方法可以用來創(chuàng)建FileOutputStream 對象。
使用字符串類型的文件名來創(chuàng)建一個輸出流對象:
OutputStream f = new FileOutputStream(“C:/java/hello”)
也可以使用一個文件對象來創(chuàng)建一個輸出流來寫文件。我們首先得使用File()方法來創(chuàng)建一個文件對象:
File f = new File(“C:/java/hello”);? OutputStream f = new FileOutputStream(f);
創(chuàng)建OutputStream 對象完成后,就可以使用下面的方法來寫入流或者進行其他的流操作:
public void close() throws IOException{}
關閉此文件輸入流并釋放與此流有關的所有系統(tǒng)資源。拋出IOException異常。
protected void finalize()throws IOException {}
這個方法清除與該文件的連接。確保在不再引用文件輸入流時調用其 close 方法。拋出IOException異常。
public void write(int w)throws IOException{}
這個方法把指定的字節(jié)寫到輸出流中。
public void write(byte[] w)
把指定數(shù)組中w.length長度的字節(jié)寫到OutputStream中。
實例? 下面是一個演示InputStream和OutputStream用法的例子:
import java.io.*;
public class fileStreamTest{
public static void main(String args[]){
try{
byte bWrite [] = {11,21,3,40,5};
OutputStream os = new FileOutputStream("test.txt");
for(int x=0; x < bWrite.length ; x++){
os.write( bWrite[x] ); // writes the bytes
}
os.close();
InputStream is = new FileInputStream("test.txt");
int size = is.available();
for(int i=0; i< size; i++){
System.out.print((char)is.read() + "? ");
}
is.close();
}catch(IOException e){
System.out.print("Exception");
}
}
}
上面的程序首先創(chuàng)建文件test.txt,并把給定的數(shù)字以二進制形式寫進該文件,同時輸出到控制臺上。? 以上代碼由于是二進制寫入,可能存在亂碼,可以使用以下代碼實例來解決亂碼問題:
//文件名 :fileStreamTest2.java
import java.io.*;
public class fileStreamTest2{
public static void main(String[] args) throws IOException {
File f = new File("a.txt");
FileOutputStream fop = new FileOutputStream(f);
// 構建FileOutputStream對象,文件不存在會自動新建
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
// 構建OutputStreamWriter對象,參數(shù)可以指定編碼,默認為操作系統(tǒng)默認編碼,windows上是gbk
writer.append("中文輸入");
// 寫入到緩沖區(qū)
writer.append("\r\n");
//換行
writer.append("English");
// 刷新緩存沖,寫入到文件,如果下面已經(jīng)沒有寫入的內(nèi)容了,直接close也會寫入
writer.close();
//關閉寫入流,同時會把緩沖區(qū)內(nèi)容寫入文件,所以上面的注釋掉
fop.close();
// 關閉輸出流,釋放系統(tǒng)資源
FileInputStream fip = new FileInputStream(f);
// 構建FileInputStream對象
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
// 構建InputStreamReader對象,編碼與寫入相同
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());
// 轉成char加到StringBuffer對象中
}
System.out.println(sb.toString());
reader.close();
// 關閉讀取流
fip.close();
// 關閉輸入流,釋放系統(tǒng)資源
}
}
Java序列化
Java? 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節(jié)序列,該字節(jié)序列包括該對象的數(shù)據(jù)、有關對象的類型的信息和存儲在對象中數(shù)據(jù)的類型。將序列化對象寫入文件之后,可以從文件中讀取出來,并且對它進行反序列化,也就是說,對象的類型信息、對象的數(shù)據(jù),還有對象中的數(shù)據(jù)類型可以用來在內(nèi)存中新建對象。整個過程都是Java虛擬機(JVM)獨立的,也就是說,在一個平臺上序列化的對象可以在另一個完全不同的平臺上反序列化該對象。類ObjectInputStream 和ObjectOutputStream是高層次的數(shù)據(jù)流,它們包含序列化和反序列化對象的方法。
ObjectOutputStream 類包含很多寫方法來寫各種數(shù)據(jù)類型,但是一個特別的方法例外:
public final void writeObject(Object x) throws IOException
上面的方法序列化一個對象,并將它發(fā)送到輸出流。相似的ObjectInputStream 類包含如下反序列化一個對象的方法:
public final Object readObject() throws IOException,ClassNotFoundException
該方法從流中取出下一個對象,并將對象反序列化。它的返回值為Object,因此,需要將它轉換成合適的數(shù)據(jù)類型。? 為了演示序列化在Java中是怎樣工作的,假設我們定義了如下的Employee類,該類實現(xiàn)了Serializable 接口:
public class Employee implements java.io.Serializable
{
public String name;
public String address;
public transient int SSN;
public int number;
public void mailCheck()
{
System.out.println("Mailing a check to " + name
+ " " + address);
}
}
請注意,一個類的對象要想序列化成功,必須滿足兩個條件:
該類必須實現(xiàn) java.io.Serializable 對象。該類的所有屬性必須是可序列化的。如果有一個屬性不是可序列化的,則該屬性必須注明是短暫的。
檢驗一個類的實例是否能序列化十分簡單, 只需要查看該類有沒有實現(xiàn)java.io.Serializable接口。
序列化對象
ObjectOutputStream 類用來序列化一個對象,如下的SerializeDemo例子實例化了一個Employee對象,并將該對象序列化到一個文件中。? 該程序執(zhí)行后,就創(chuàng)建了一個名為employee.ser文件。該程序沒有任何輸出,但是可以通過代碼研讀來理解程序的作用。? 注意: 當序列化一個對象到文件時, 按照Java的標準約定是給文件一個.ser擴展名。
import java.io.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try
{
FileOutputStream fileOut =
new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
反序列化對象
下面的DeserializeDemo程序實例了反序列化,/tmp/employee.ser存儲了Employee對象:
import java.io.*;
public class DeserializeDemo
{
public static void main(String [] args)
{
Employee e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("SSN: " + e.SSN);
System.out.println("Number: " + e.number);
}
}
以上運行結果如下:
Deserialized Employee…? Name: Reyan Ali? Address:Phokka Kuan, Ambehta Peer? SSN: 0? Number:101
這里要注意以下要點:
readObject() 方法中的try/catch代碼塊嘗試捕獲 ClassNotFoundException異常。對于JVM可以反序列化對象,它必須是能夠找到字節(jié)碼的類。如果JVM在反序列化對象的過程中找不到該類,則拋出一個 ClassNotFoundException異常。? 注意,readObject()方法的返回值被轉化成Employee引用。? 當對象被序列化時,屬性SSN的值為111222333,但是因為該屬性是短暫的,該值沒有被發(fā)送到輸出流。所以反序列化后Employee對象的SSN屬性為0
Java異常處理
異常是程序中的一些錯誤,但并不是所有的錯誤都是異常,并且錯誤有時候是可以避免的。? 比如說,你的代碼少了一個分號,那么運行出來結果是提示是錯誤java.lang.Error;如果你用System.out.println(11/0),那么你是因為你用0做了除數(shù),會拋出java.lang.ArithmeticException的異常。? 異常發(fā)生的原因有很多,通常包含以下幾大類:
用戶輸入了非法數(shù)據(jù)要打開的文件不存在網(wǎng)絡通信時連接中斷,或者JVM內(nèi)存溢出
這些異常有的是因為用戶錯誤引起,有的是程序錯誤引起的,還有其它一些是因為物理錯誤引起的。-? 要理解Java異常處理是如何工作的,你需要掌握以下三種類型的異常:
檢查性異常:最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預見的。例如要打開一個不存在文件時,一個異常就發(fā)生了,這些異常在編譯時不能被簡單地忽略運行時異常: 運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常可以在編譯時被忽略錯誤: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發(fā)生了,它們在編譯也檢查不到的
Exception類的層次
所有的異常類是從java.lang.Exception類繼承的子類。? Exception類是Throwable類的子類。除了Exception類外,Throwable還有一個子類Error 。? Java程序通常不捕獲錯誤。錯誤一般發(fā)生在嚴重故障時,它們在Java程序處理的范疇之外。? Error用來指示運行時環(huán)境發(fā)生的錯誤。
例如,JVM內(nèi)存溢出。一般地,程序不會從錯誤中恢復。? 異常類有兩個主要的子類:IOException類和RuntimeException類。
捕獲異常
使用try和catch關鍵字可以捕獲異常。try/catch代碼塊放在異常可能發(fā)生的地方。? try/catch代碼塊中的代碼稱為保護代碼,使用 try/catch的語法如下:
try
{
// 程序代碼
}catch(ExceptionName e1)
{
//Catch 塊
}
Catch語句包含要捕獲異常類型的聲明。當保護代碼塊中發(fā)生一個異常時,try后面的catch塊就會被檢查。? 如果發(fā)生的異常包含在catch塊中,異常會被傳遞到該catch塊,這和傳遞一個參數(shù)到方法是一樣。
實例? 下面的例子中聲明有兩個元素的一個數(shù)組,當代碼試圖訪問數(shù)組的第三個元素的時候就會拋出一個異常:
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown? :" + e);
}
System.out.println("Out of the block");
}
}
以上運行結果如下:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3? Out of the block
多重捕獲塊
一個try代碼塊后面跟隨多個catch代碼塊的情況就叫多重捕獲。? 多重捕獲塊的語法如下所示:
try{
// 程序代碼
}catch(異常類型1 異常的變量名1){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}
上面的代碼段包含了3個catch塊。? 可以在try語句后面添加任意數(shù)量的catch塊。? 如果保護代碼中發(fā)生異常,異常被拋給第一個catch塊。? 如果拋出異常的數(shù)據(jù)類型與ExceptionType1匹配,它在這里就會被捕獲。? 如果不匹配,它會被傳遞給第二個catch塊。? 如此,直到異常被捕獲或者通過所有的catch塊。(與C++一樣)
實例? 該實例展示了怎么使用多重try/catch:
try
{
file = new FileInputStream(fileName);
x = (byte) file.read();
}catch(IOException i)
{
i.printStackTrace();
return -1;
}catch(FileNotFoundException f) //Not valid!
{
f.printStackTrace();
return -1;
}
throws/throw關鍵字:
如果一個方法沒有捕獲一個檢查性異常,那么該方法必須使用throws 關鍵字來聲明。throws關鍵字放在方法簽名的尾部。? 也可以使用throw關鍵字拋出一個異常,無論它是新實例化的還是剛捕獲到的。? 下面方法的聲明拋出一個RemoteException異常:
import java.io.*;
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開。? 例如,下面的方法聲明拋出RemoteException和InsufficientFundsException:
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
finally關鍵字
finally關鍵字用來創(chuàng)建在try代碼塊后面執(zhí)行的代碼塊。? 無論是否發(fā)生異常,finally代碼塊中的代碼總會被執(zhí)行。? 在finally代碼塊中,可以運行清理類型等收尾善后性質的語句。
finally代碼塊出現(xiàn)在catch代碼塊最后,語法如下:
try{
// 程序代碼
}catch(異常類型1 異常的變量名1){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}finally{
// 程序代碼
}
實例:
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown? :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
以上運行結果如下:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException:? 3 First element value: 6? The finally statement is executed
注意下面事項:
catch不能獨立于try存在。在try/catch后面添加finally塊并非強制性要求的。try代碼后不能既沒catch塊也沒finally塊。try, catch, finally塊之間不能添加任何代碼。
聲明自定義異常
在Java中可以自定義異常。編寫自己的異常類時需要記住下面的幾點。
所有異常都必須是Throwable的子類。如果希望寫一個檢查性異常類,則需要繼承Exception類。如果想寫一個運行時異常類,那么需要繼承RuntimeException 類。
可以像下面這樣定義自己的異常類:
class MyException extends Exception{ }
只繼承Exception 類來創(chuàng)建的異常類是檢查性異常類。? 下面的InsufficientFundsException類是用戶定義的異常類,它繼承自Exception。? 一個異常類和其它任何類一樣,包含有變量和方法。? 實例:
// 文件名InsufficientFundsException.java
import java.io.*;
public class InsufficientFundsException extends Exception
{
private double amount;
public InsufficientFundsException(double amount)
{
this.amount = amount;
}
public double getAmount()
{
return amount;
}
}
為了展示如何使用我們自定義的異常類,? 在下面的CheckingAccount 類中包含一個withdraw()方法拋出一個InsufficientFundsException異常:
// 文件名稱 CheckingAccount.java
import java.io.*;
public class CheckingAccount
{
private double balance;
private int number;
public CheckingAccount(int number)
{
this.number = number;
}
public void deposit(double amount)
{
balance += amount;
}
public void withdraw(double amount) throws
InsufficientFundsException
{
if(amount <= balance)
{
balance -= amount;
}
else
{
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
public double getBalance()
{
return balance;
}
public int getNumber()
{
return number;
}
}
下面的BankDemo程序示范了如何調用CheckingAccount類的deposit() 和withdraw()方法:
//文件名稱 BankDemo.java
public class BankDemo
{
public static void main(String [] args)
{
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try
{
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00);
}catch(InsufficientFundsException e)
{
System.out.println("Sorry, but you are short $"
+ e.getAmount());
e.printStackTrace();
}
}
}
編譯上面三個文件,并運行程序BankDemo,得到結果如下所示:
Depositing $500…
Withdrawing $100…
Withdrawing
600...Sorry,butyouareshort
600... Sorry, but you are short 200.0? InsufficientFundsException? at CheckingAccount.withdraw(CheckingAccount.java:25)? at BankDemo.main(BankDemo.java:13)
總結
以上是生活随笔為你收集整理的java i o流异常问题_第四章 Java的I/O流和异常处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 计算小费_java-以某些形状
- 下一篇: jsonp java后台_jsonp与J