1 IO
1.1 IO的分類
根據數據流向分類
- 輸入流:把數據從其他設備讀取到內存
以InputStream,Reader結尾
- 輸出流:把數據從內存中寫出到其他設備
以OutputStream、Writer結尾
根據數據類型分類
- 字節流:已字節爲單位,讀寫數據
以InputStream和OutputStream結尾
- 字符流:以字符爲單位,讀寫數據
以Reader和Writer結尾
根據IO流的角色不同
-
節點流:可以從或向一個特定的地方(節點)讀寫數據
-
處理流:是對一個已經存在的流進行連接和封裝,通過所封裝的流的功能調用實現數據讀寫
常用的節點流
- 文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件進行處理的節點流。
- 字符串 StringReader StringWriter 對字符串進行處理的節點流。
- 數 組 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter 對數組進行處理的節點流(對應的不再是文件,而是內存中的一個數組)。
- 管 道 PipedInputStream、PipedOutputStream、PipedReader、PipedWriter對管道進行處理的節點流。
常用處理流
- 緩衝流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter—增加緩衝功能,避免頻繁讀寫硬盤。
- 轉換流:InputStreamReader、OutputStreamReader—實現字節流和字符流之間的轉換。
- 對象流:ObjectInputStream、ObjectOutputStream–提供直接讀寫Java對象功能
1.2 字節輸入流【InputStream】
1.2.1 FileInputStream類
java.io.FileInputStream 類是文件輸入流,從文件中讀取字節
-
構造方法
FileInputStream(File file) : 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
FileInputStream(String name) : 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。
-
構造代碼示例
File file = new File("c:/aa/a.txt"); FileInputStream in1 = new FileInputStream(file); //File類型參數 FileInputStream in2 = new FileInputStream("c:/aa/a.txt"); //String參數
1.2.2 讀取字節數據
讀取字節
-
read
()方法,每次可以讀取一個字節的數據,提升爲int類型,讀取到文件末尾,返回-1 -
示例代碼(循環讀取)
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.imageio.stream.FileImageInputStream; public class Test7 { public static void main(String[] args) { File file = new File("c:/aa/a.txt"); FileInputStream in1 = null; try { in1 = new FileInputStream(file); //File類型參數 // FileInputStream in2 = new FileInputStream("c:/aa/a.txt"); //String參數 int b; while((b = in1.read()) != -1){ System.out.println((char)b); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { in1.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
-
使用字節數組讀取:
read(byte[] b)
,每次讀取b的長度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回-1
,代碼使用演示:循環讀取
public class Test6 { public static void main(String[] args) { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("c:/aaa/java.txt"); byte b[] = new byte[5]; int len = 0; while((len = in.read(b)) != -1){ System.out.println(new String(b,0,len)); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
1.3 字節輸出流【OutputStream】
java.io.OutputStream 抽象類是表示字節輸出流的所有類的超類,將指定的字節信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。
- public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
public void flush()
:刷新此輸出流並強制任何緩衝的輸出字節被寫出。public void write(byte[] b)
:將 b.length字節從指定的字節數組寫入此輸出流。public void write(byte[] b, int off, int len)
:從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。public abstract void write(int b)
:將指定的字節輸出流。
1.3.1 FileOutputStream類
-
構造方法
-
public FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。
-
public FileOutputStream(String name)
: 創建文件輸出流以指定的名稱寫入文件。示例代碼
public class FileOutputStreamConstructor throws IOException { public static void main(String[] args) { // 使用File對象創建流對象 File file = new File("a.txt"); FileOutputStream fos = new FileOutputStream(file); // 使用文件名稱創建流對象 FileOutputStream fos = new FileOutputStream("b.txt"); } }
-
-
寫出字節數據
write(int b)
方法,每次可以寫出一個字節數據write(byte[] b)方法,每次可以寫出數組中的數據
示例代碼:
FileOutputStream fos = new FileOutputStream("c:/aaa/text.txt"); // 字符串轉換爲字節數組 byte[] b = {97,98,99,100,101}; // 寫出字節數組數據 fos.write(b); // 關閉資源 fos.close();
寫出指定長度字節數組:
write(byte[] b, int off, int len)
,每次寫出從off索引開始,len個字節示例代碼:
FileOutputStream fos = new FileOutputStream("c:/aaa/text.txt"); // 字符串轉換爲字節數組 byte[] b = "abcde".getBytes(); // 寫出從索引2開始,2個字節。索引2是c,兩個字節,也就是cd。 fos.write(b,2,2); // 關閉資源 fos.close();
1.3.2 方法運用
例如將”c:/aaa/java.txt“拷貝到”c:/bbb/java1.txt“
示例代碼
public class Test {
public static void main(String[] args) {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("c:/aaa/java.txt");
out = new FileOutputStream("c:/bbb/java1.txt");
byte b[] = new byte[5];
int len = 0;
while((len = in.read(b)) != -1){
out.write(b, 0, len);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
1.4 字符輸入流【Reader】
1.4.1 常用方法
- public void close() :關閉此流並釋放與此流相關聯的任何系統資源
- public int read() : 從輸入流讀取一個字符
- public int read(char[] cbuf) : 從輸入流中讀取一些字符,並將它們存儲到字符數組 cbuf中
1.4.2 FileReader類
構造方法
-
FileReader(File file) : 創建一個新的 FileReader ,給定要讀取的File對象
-
FileReader(String fileName) : 創建一個新的 FileReader ,給定要讀取的文件的名稱
-
示例代碼
FileReader in = new FileReader("c:/aa/bb/java.txt"); //使用了第二種構造器
讀取字符
- 核心代碼
int i = 0; //read()方法
while((i = in.read()) != -1){
System.out.print((char)i);
}
in.close;
//第二種方法 使用數組讀取
int len = 0;
char[] b = new char[1024];
while((len = in.read(b)) != -1){
System.out.print(new String(b,0,len));
}
in.close;
1.5 字符輸出流【Writer】
1.5.1 常用方法
- void write(int c) 寫入單個字符。
void write(char[] cbuf)
寫入字符數組。abstract void write(char[] cbuf, int off, int len)
寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。void write(String str)
寫入字符串。void write(String str, int off, int len)
寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。void flush()
刷新該流的緩衝。void close()
關閉此流,但要先刷新它。
1.5.2 FileWriter類
構造方法
-
FileWriter(File file) : 創建一個新的 FileWriter,給定要讀取的File對象。
-
FileWriter(String fileName)
: 創建一個新的 FileWriter,給定要讀取的文件的名稱。 -
示例代碼
FileWriter fw = new FileWriter("c:/aa/bb/java.txt"); //使用第二種構造方法
寫出數據
-
write(int value)方法
fw.write(97); //write(int value)方法
-
flush()與close()方法
因爲內置緩衝區的原因,如果不關閉輸出流,無法寫出字符到文件中。但是關閉的流對象,是無法繼續寫出數據的。如果我們既想寫出數據,又想繼續使用流,就需要
flush
方法了- flush :刷新緩衝區,流對象可以繼續使用。
close
:先刷新緩衝區,然後通知系統釋放資源。流對象不可以再被使用了。
-
write(char[] cbuf)
和
write(char[] cbuf, int off, int len)方法char[] a = {'你','好','啊'}; fw.write(a); fw.write(a,1,2) // 寫出從索引1開始,2個字節。索引1是'好',兩個字節,也就是'好啊'
-
write(String str)
和 write(String str, int off, int len)方法String name = "湯小強"; fw.write(name); fw.write(name,1,2); //結果"小強"
1.6 緩衝流
1.6.1 字節緩衝流
構造方法
-
public BufferedInputStream(InputStream in) :創建一個 新的緩衝輸入流。
-
public BufferedOutputStream(OutputStream out)
: 創建一個新的緩衝輸出流。 -
示例代碼
BufferedInputStream bis = new BuffBufferedInputStream(new FileInputStream("c:/aa/bb/java.txt")); BufferedOutputStream bos = new BuffBufferedOutputStream(new FileOutputStream("c:/aa/bb/java.txt"));
-
優點:效率高
1.6.2 字符緩衝流
構造方法
-
public BufferedReader(Reader in) :創建一個 新的緩衝輸入流。
-
public BufferedWriter(Writer out)
: 創建一個新的緩衝輸出流。 -
示例代碼
BufferedReader br = new BufferedReader(new FileReader("c:/aa/bb/java.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("c:/aa/bb/java.txt"));
特有方法
-
BufferedReader:
public String readLine()
: 讀一行文字。 -
BufferedWriter:
public void newLine()
: 寫一行行分隔符,由系統屬性定義符號。 -
示例代碼
String line = null; // 循環讀取,讀取到最後返回null while ((line = br.readLine())!=null) { System.out.print(line); System.out.println("------"); } //newLine() bw.write("湯"); // 寫出換行 bw.newLine(); bw.write("小"); bw.newLine();
1.7 轉換流
1.7.1 InputStreamReader類
構造方法
-
InputStreamReader(InputStream in) : 創建一個使用默認字符集的字符流。
-
InputStreamReader(InputStream in, String charsetName)
: 創建一個指定字符集的字符流 -
舉例代碼
InputStreamReader isr = new InputStreamReader(new FileInputStream("c:/aa/bb/java.txt")); //下面指定了程序的讀取文件類型 InputStreamReader isr2 = new InputStreamReader(new FileInputStream("c:/aa/bb/java_GBK.txt") , "GBK");//可以讀取GBK文件,即使程序本身不是GBK
指定編碼讀取
while ((read = isr2.read()) != -1) {
System.out.print((char)read);//
}
isr2.close();
1.7.2 OutputStreamWriter類
構造方法
-
OutputStreamWriter(OutputStream in) : 創建一個使用默認字符集的字符流。
-
OutputStreamWriter(OutputStream in, String charsetName)
: 創建一個指定字符集的字符流。 -
示例代碼
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c:/aa/bb/java.txt")); //指定程序寫出的編碼 OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("c:/aa/bb/java.txt"), "GBK");
指定編碼寫出
//文件保存編碼爲GBK
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("c:/aa/bb/java.txt") , "GBK");
osw2.write("你好");
案例
public class Test {
//將gbk格式的文件轉換爲utf-8格式存儲
public static void main(String[] args) {
Reader in = null;
Writer out = null;
try {
in = new InputStreamReader(
new FileInputStream("c:/aa/bb/java_gbk.txt"), "gbk");
out = new OutputStreamWriter(
new FileOutputStream("c:/aa/bb/java_gbk.txt"), "utf-8");
int i = 0;
while((i = in.read()) != -1){
out.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
in.close();
out.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
1.8 序列化
1.8.1 ObjectOutputStream類
java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到文件,實現對象的持久存儲。
構造方法
-
public ObjectOutputStream(OutputStream out) : 創建一個指定OutputStream的ObjectOutputStream
-
示例代碼
ObjectOutputStream out = new ObjectOutputStream(new FileoutputStream("c:/aa/bb/java.txt"));
序列化注意事項
- 該類必須實現
java.io.Serializable
接口 - 該類的所有屬性必須是可序列化的
- 靜態變量的值不會序列化
1.8.2 ObjectInputStream類
ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復爲對象
構造方法
public ObjectInputStream(InputStream in) : 創建一個指定InputStream的ObjectInputStream。
1.8.3 案例演示
代碼示例
public class Test {
public static void main(String[] args) {
/*
* 聲明一個Message類
* 包含:發送者(sender)、接收者(recipient)、消息內容(content)、發送時間(time)
* 創建一個Message對象,並寫到message.dat文件中,並再次讀取顯示
*/
Message message = new Message("tom", "jack", "請儘快回覆", "2020年05月28號晚 20:00");
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("c:/aa/bb/message.dat"));
ObjectInputStream ois=new ObjectInputStream(
new FileInputStream("c:/aa/bb/message.dat"));
oos.writeObject(message);
Object object = ois.readObject();
System.out.println(object);
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Message implements Serializable{
private String sender;
private String recipient;
private String content;
private String time;
public Message(String sender, String recipient, String content, String time) {
super();
this.sender = sender;
this.recipient = recipient;
this.content = content;
this.time = time;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
public String toString() {
return "Message [sender=" + sender + ", recipient=" + recipient + ", content=" + content + ", time=" + time
+ "]";
}
}