一、IO流的概述
1. 流的類型
- 操作數據單位:字節流、字符流
- 數據的流向:輸入流、輸出流
- 流的角色:節點流、處理流
圖解
以字體顏色劃分類別
2. 體系結構
重點學習藍色框中的內容
3. 輸入、輸出的基本步驟
輸入過程
- 創建File類的對象,指明讀取的數據的來源。(要求此文件一定要存在)
- 創建相應的輸入流,將File類的對象作爲參數,傳入流的構造器中
- 具體的讀入過程: 創建相應的byte[] 或 char[]。
- 關閉流資源
說明:程序中出現的異常需要使用try-catch-finally處理。
輸出過程
- 創建File類的對象,指明寫出的數據的位置。(不要求此文件一定要存在)
- 創建相應的輸出流,將File類的對象作爲參數,傳入流的構造器中
- 具體的寫出過程: write(char[]/byte[] buffer,0,len)
- 關閉流資源
說明:程序中出現的異常應使用try-catch-finally處理。
二、字符流
字符流只能處理文本文件(例如:.txt,.java,.c,.cpp)。
1. 字符輸入流
@Test public void testFileReader() {
FileReader fr = null;
try {
//1. File的實例化
File file = new File("testFileReader.txt");
//2. 實例化 FileReader流
fr = new FileReader(file);
//3. 進行讀入操作
//read(char[] charbuffer):返回每次讀入到數組中的字符個數,若達到文件末尾則返回-1
char[] charbuffer = new char[5];
int len;
while ((len = fr.read(charbuffer)) != -1) {
//方式一:
//for (int i = 0; i < len; i++) {
// System.out.print(charbuffer[i]);
//}
//方式二:
String str = new String(charbuffer, 0, len);
System.out.print(str);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//4. 流的關閉
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 字符輸出流
@Test public void testFileWriter() {
//1. File的實例化
File file = new File("testFileWriter.txt");
FileWriter fw = null;
try {
//2. FileWriter
fw = new FileWriter(file);
//3. 進行寫出操作
fw.write("Hello, ");
fw.write("world ! ");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 流的關閉
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、字節流
字節流可處理所有文件
字節輸入流/字節輸出流
運用兩種字節流進行文件複製操作
public void fileInputOutputStreamTest() throws IOException {
//1. 創建File類對象,指定讀入與寫出的文件
File srcFile = new File("img1.jpg");
File destFile = new File("copy.jpg");
//2. 創建輸入輸出流
FileInputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
//3. 數據的讀入與寫出操作
byte[] buffer = new byte[1024];
//記錄字符個數
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
//每次寫出len個字符
fileOutputStream.write(buffer, 0, len);
}
//4.關閉流 - 建議從後向前關閉流
fileOutputStream.close();
fileInputStream.close();
}
四、緩衝流
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
緩衝流作用:提供流的讀取、寫入的速度
提高讀寫速度的原因:內部提供了一個緩衝區。默認情況下是8kb
1. 字符緩衝流
@Test
public void testBufferedReaderWriter() throws IOException {
//1.實例化文件和流
BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("copy.txt")));
//2.進行數據讀寫
char[] charbuffer = new char[1024];
int len;
while((len = br.read(charbuffer)) != -1){
bw.write(charbuffer,0,len);
}
//3. 關閉資源
bw.close();
br.close();
}
2. 字節緩衝流
@Test
public void copyFileWithBuffered() throws IOException {
//1. 創建File類對象,指定讀入與寫出的文件
File srcFile = new File("img1.jpg");
File destFile = new File("copy.jpg");
//2. 創建輸入輸出流
InputStream fileInputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
//3. 創建緩衝流
BufferedInputStream bis = new BufferedInputStream(fileInputStream);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
//4. 數據的讀入與寫出操作
byte[] buffer = new byte[1024];
//記錄字符個數
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
//每次寫出len個字符
bos.write(buffer, 0, len);
}
//5.關閉流 - 建議從後向前關閉流
bos.close();
bis.close();
}
五、字符轉換流
由於字符存在編碼問題,轉換流用於解決字符轉碼問題。
1. 輸入字符轉換流
@Test public void inputStreamReaderTest() throws IOException {
FileInputStream fis = new FileInputStream("hello.txt");
//InputStreamReader isr = new InputStreamReader(fis);//使用系統默認的字符集
//參數2指明瞭字符集,具體使用哪個字符集,取決於文件dbcp.txt保存時使用的字符集
//使用系統默認的字符集 默認爲 UTF-8
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1) {
String str = new String(cbuf, 0, len);
System.out.print(str);
}
isr.close();
}
2. 輸出字符轉換流
該例子爲綜合輸入和輸出字符轉換流
@Test
public void outputStreamWriterTest() throws Exception {
//1.造文件、造流
File file1 = new File("hello.txt");
File file2 = new File("hello_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
//2.讀寫過程
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf, 0, len);
}
//3.關閉資源
isr.close();
osw.close();
}
六、對象流
自定義類型的對象使用對象流的條件:
- 需要實現接口:Serializable
- 當前類提供一個全局常量:serialVersionUID
- 除了當前類需要實現Serializable接口之外,還必須保證其內部所屬性也必須是可序列化的。(默認情況下,基本數據類型可序列化)
補充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
import org.junit.Test;
import java.io.*;
public class ObjectInputOutputStreamTest {
/**
* 對象輸出流
*/
@Test
public void objectOutputStreamTest() {
ObjectOutputStream oos = null;
try {
//1.
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
//2.
oos.writeObject(new String("I like Java"));
oos.flush();//刷新操作
oos.writeObject(new Student("張三", 23));
oos.flush();
oos.writeObject(new Student("李四", 23, 1001));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
//3.
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 對象輸入流
*/
@Test
public void objectInputStreamTest() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String)obj;
Student student = (Student)ois.readObject();
Student student1 = (Student)ois.readObject();
System.out.println(str);
System.out.println(student);
System.out.println(student1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//實體類/自定義類型
class Student implements Serializable{
private static final long serialVersionUID = -121294470754667710L;
private String name;
private int age;
private int score;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}';
}
}
七、RandomAccessFile/隨機存取文件流
- RandomAccessFile直接繼承於java.lang.Object類,實現了DataInput和DataOutput接口。
- RandomAccessFile既可以作爲一個輸入流,又可以作爲一個輸出流。
- 如果RandomAccessFile作爲輸出流時,寫出到的文件如果不存在,則在執行過程中自動創建。
如果寫出到的文件存在,則會對原文件內容進行覆蓋。(默認情況下,從頭覆蓋) - 可以通過seek(int pos) ,實現RandomAccessFile插入數據的效果。
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
/**
* 實現複製粘貼
* @throws IOException
*/
@Test public void randomAccessFileTest1() throws IOException {
//1.創建流
RandomAccessFile raf1 = new RandomAccessFile(new File("img.jpg"), "r");
RandomAccessFile raf2 = new RandomAccessFile(new File("img1.jpg"), "rw");
//2.創建緩衝區
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
//3.關閉流
raf1.close();
raf2.close();
}
/**
* 使用RandomAccessFile實現數據的插入效果
*/
@Test public void randomAccessFileTest2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
//將指針調到角標爲3的位置
raf1.seek(3);
//保存指針3後面的所數據到StringBuilder中
StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while ((len = raf1.read(buffer)) != -1) {
builder.append(new String(buffer, 0, len));
}
//調回指針
raf1.seek(3);
raf1.write("AAA".getBytes());
//將StringBuilder中的數據寫入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
}
}
八、Path、Paths、Files的使用
1. Path
Path用於替換原有的File類。
該接口的實現是不可變且安全的,可供多個並行線程使用。
2. Paths
此類僅由靜態方法組成,通過轉換路徑字符串返回Path或URI 。
Paths類提供了get()方法用來獲取Path對象。
Paths的常用方法
3. Files
主要用於操作文件或文件目錄的工具類
常用方法