java核心技術-IO
一 .IO
1.1 流的簡單介紹和分類
Java流操作的相關的類和介面:
Java流類圖結構:
四個抽象基類分別為:InputStream 、OutputStream 、Reader 、Writer;
流的概念:在Java中將輸入輸出抽象稱為為流,就好像水管,將兩個容器連線起來。流是一組有順序的,有起點和終點的位元組集合,是對資料傳輸的總稱和抽象,即資料在兩裝置間的傳輸稱為流
Java中IO所採用的設計模式:裝飾者模式
分類:
1.按流向不同:輸入流,輸出流(以程式為主體)
2.按型別不同:位元組流,字元流(字元流用於操作文字檔案 .txt .java 位元組流用於操作非文字檔案 .avi .rmvg .jpg .mp3)
3.按角色不同:節點流,處理流
注:若用位元組流操作文字檔案,會引起亂碼和效率低的問題。若用字元流去操作非文字檔案,不會報錯,但什麼也獲取不了。
1.2 常見節點流和處理流的使用方法
1.2.1 只使用節點流的複製貼上:
非文字檔案:
FileInputStream fis = null; FileOutputStream fos = null; try { //1.建立 FileInputStream 的例項,同時開啟指定檔案 fis = new FileInputStream("1.jpg"); fos = new FileOutputStream("2.jpg"); byte[] b = new byte[1024]; int len = 0; while((len = fis.read(b)) != -1){ fos.write(b,0,len); } } catch (Exception e) { e.printStackTrace(); } finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } }
文字檔案:
FileReader fr = null; FileWriter fw = null; try { fr = new FileReader("1.txt"); fw = new FileWriter("2.txt"); char[] c = new char[100]; int len = 0; while((len = fr.read(c)) != -1){ fw.write(c, 0, len); } } catch (Exception e) { e.printStackTrace(); } finally { if(fw != null){ try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } if(fr != null){ try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
1.2.2 帶上緩衝流的複製貼上
非文字檔案:
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = new FileOutputStream("2.jpg");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
bos.write(b, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
if(bos != null){
bos.close();
}
if(bis != null){
bis.close();
}
}
文字檔案:
BufferedReader br = null;
BufferedWriter bw = null;
try {
FileReader fr = new FileReader("newFile.txt");
FileWriter fw = new FileWriter("newFile2.txt");
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
String str = null;
while( (str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(bw != null){
bw.close();
}
if(br != null){
br.close();
}
}
1.3 序列化與反序列化
主要使用物件流進行操作: ObjectInputStream 、ObjectOutputStream
序列化:將記憶體中的物件以二進位制的形式儲存在磁碟中
反序列化:將磁碟的物件讀取
準備工作: 需要提供一個序列化介面。序列號如果不顯示給出, 則會預設根據類資訊自動生成一個序列號,一旦類資訊傳送變動與序列化前不同,物件的反序列化將會丟擲異常,所以還是建議 顯示給出一個序列號。
關鍵字: transient 和 static修飾的屬性不會被序列化
1.3.1 序列化反序列化多個值
---序列化:
//3. 建立物件流,包裝緩衝流,用於完成序列化
ObjectOutputStream oos = null;
try {
int num = 10;
boolean flag = false;
String str = "abcde";
//1.建立節點流,同時開啟指定檔案
FileOutputStream fos = new FileOutputStream("./data.dat");
//2.(可選)使用緩衝流包裝節點流,用於提高傳輸效率。
BufferedOutputStream bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
oos.writeInt(num);
oos.writeBoolean(flag);
oos.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null){
//5.關閉流
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
---反序列化:
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("./data.dat");
ois = new ObjectInputStream(fis);
//反序列化的順序務 必和 序列化的順序保持一致
int num = ois.readInt();
boolean flag = ois.readBoolean();
String str = ois.readUTF();
System.out.println(num);
System.out.println(flag);
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.3.2 序列化和反序列化多個物件
---準備工作:
public class Person implements Serializable{
private static final long serialVersionUID = 134628734823487283L;
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
---序列化:
//Person 務必要實現序列化介面
Person p1 = new Person("張三",19);
Person p2 = new Person("李四",20);
Person p3 = new Person("王五",16);
ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream("person.dat");
BufferedOutputStream bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
oos.writeObject(p1);
oos.writeObject(p2);
oos.writeObject(p3);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
---反序列化:
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("person.dat");
BufferedInputStream bis = new BufferedInputStream(fis);
ois = new ObjectInputStream(bis);
Person p1 = (Person)ois.readObject();
Person p2 = (Person)ois.readObject();
Person p3 = (Person)ois.readObject();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.4 轉換流
轉換流:InputStreamReader & OutStreamWriter
編碼:字串 -> 位元組陣列
解碼:位元組陣列 -> 字串
BufferedReader br = null;
BufferedWriter bw = null;
try {
FileInputStream fis = new FileInputStream("hello.txt");
InputStreamReader isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
FileWriter fileWriter = new FileWriter("hello1.txt");
bw = new BufferedWriter(fileWriter);
String str = null;
while((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.5 隨機存取檔案類
RandomAccessFile 類支援"隨機訪問"的方式,程式可以跳到檔案的任意地方來讀寫檔案
支援只訪問檔案的部分內容
可以向已存在的檔案後追加內容
RandomAccessFile 物件包含一個記錄指標,用以標示當前讀寫處的位置。
RandomAccessFile 類物件可以自由移動記錄指標:
long getFilePointer():獲取檔案記錄指標的位置
void seek(long pos):將檔案記錄指標定位到pos位置
- 構造器
public RandomAccessFile(File file,String mode)
public RandomAccessFile(String name,String mode)
- 建立RandomAccessFile 類例項需要制定一個mode 引數, 該引數指定 RandomAccessFile的訪問模式:
r:以只讀方式開啟
rw:開啟以便讀取和寫入
rwd:開啟以便讀取和寫入;同步檔案內容的更新
rws:開啟以便讀取和寫入;同步檔案內容和元資料的更新
/**
* 在abcdef寫入檔案 再向abc中間 插入hello
*/
@Test
public void test4() throws IOException{
RandomAccessFile randomAccessFile = new RandomAccessFile("hell.txt", "rw");
String str = "abcdef";
randomAccessFile.write(str.getBytes());
randomAccessFile.seek(3);
String line = randomAccessFile.readLine();
randomAccessFile.seek(3);
randomAccessFile.write("hello".getBytes());
randomAccessFile.write(line.getBytes());
randomAccessFile.close();
}