IO 概述
什么是 IO
Java中IO操作主要是指使用java.io包下的內容,進行輸入、輸出操作。輸入也叫做讀取數據,輸岀也叫做作寫出數據。
IO的分類
根據數據的流向分為:輸入流和輸出流。
輸入流:把數據從其他設備上讀取到內存中的流。
輸出流:把數據從內存中寫出到其他設備上的流。
格局數據的類型分為:字節流和字符流。
頂級父類們
字節流
一切文件數據(文本、圖片、視頻等)在存儲時,都是以二進制數字的形式保存,都是一個ー個的字節,在傳輸時也是一樣如此。所以,字節流可以傳輸任意文件數據。在操作流的時候,我們要時刻明確,無論使用什么樣的流對象,底層傳輸的始終為二進制數據。
字節輸出流——OutputStream
java.io.OutputStream抽象類是表示字節輸出流的所有類的超類,將指定的字節信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。
java.io.OutputStream
public abstract void write(int b) throws IOException;
// 將指定的字節輸出流。
public void write(byte b[]) throws IOException{...};
// 將b.length字節從指定的字節數組寫入此輸出流。
public void write(byte b[], int off, int len) throws IOException{...};
// 從指定的字節數組寫入len字節,從偏移量off開始輸出到此輸出流。
public void flush() throws IOException{};
// 刷新此輸出流並強制任何緩沖的輸出字節被寫出。
public void close() throws IOException {};
// 關閉此輸出流並釋放與此流相關聯的任何系統資源。
FileOutputStream類
- OutputStream抽象類,有很多的子類,其中FileOutputStream類是它其中一個簡單的子類。
- java.io.FileOutputStream是文件輸出流,用於將數據寫出到文件。
寫出字節數據
寫出字節:write(int b)方法,每次可以寫出一個字節數據
字節輸出流的使用步驟:
- 創建一個 FileOutputStream對象,構造方法中傳遞寫入數據的目的地。
- 調用FileOutputStream對象中的方法write,把數據寫入到文件中。
- 釋放資源(流使用會占用一定的內存,使用完畢要把內存清空提供程序的效率)。
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoFosWrite {
public static void main(String[] args) throws IOException {
// 使用文件名創建字節流對象
FileOutputStream fos = new FileOutputStream("FOS.txt");
// 寫出數據
// 寫出第一個字節
fos.write(97);
// 寫出第二個字節
fos.write(98);
// 寫出第三個字節
fos.write(99);
// 關閉資源
fos.close();
}
}
運行結果:生成了一個"FOS.txt"文件
FOS.txt文件大小是3個字節,內容是abc
寫入數據的原理(內存-->硬盤):
Java程序 --> Java虛擬機 --> 操作系統 --> 操作系統調用寫數據的方法 --> 把數據寫到文件中
寫數據的時候,會把要寫入的數據轉換為二進制數。在打開文件的時候,都會查詢編碼表(例如:ASCII表),把字節轉換為字符表示。
write(byte b[])方法
作用:將b.length字節從指定的字節數組寫入此輸出流。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS1.txt");
byte[] bytes = {97, 98, 99};
// 將3個字節從bytes字節數組寫入fos輸出流。
fos.write(bytes);
fos.close();
}
}
運行結果:生成了一個"FOS1.txt"文件
write(byte b[], int off, int len)方法
作用:從指定的字節數組寫入len字節,從偏移量off開始輸出到此輸出流。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS2.txt");
byte[] bytes = {97, 98, 99, 100, 101, 102};
// 將3個字節從bytes字節數組寫入fos輸出流。
fos.write(bytes, 1, 4);
fos.close();
}
}
運行結果:生成了一個"FOS2.txt"文件
write方法簡單練習
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class Demo03Write {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("FOS3.txt");
// 調用String類中的getBytes()方法,把一串字符轉換為byte數組
byte[] bytes = "大佬,你好!".getBytes();
// 將該數組轉換為集合輸出
System.out.println(Arrays.toString(bytes));
// 將多個字節從bytes字節數組寫入fos輸出流。
fos.write(bytes);
fos.close();
}
}
控制台輸出
[-27, -92, -89, -28, -67, -84, -17, -68, -116, -28, -67, -96, -27, -91, -67, -17, -68, -127]
運行結果:還生成了一個"FOS3.txt"文件
字節輸出流的續寫和換行
public FileOutputStream(File file, boolean append)
// 創建文件輸出流以寫入由指定的File對象表示的文件。
public FileOutputStream(String name, boolean append)
// 創建文件輸出流以指定的名稱寫入文件。
這兩個構造方法,參數中都需要傳入一個 boolean類型的值,true表示追加數據,false表示清空原有數據這樣創建的輸出流對象,就可以指定是否追加續寫了,代碼使用演示:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01OutputAppend {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt", true);
// 往"a.txt"文件中寫入"大佬,"內容
byte[] bytes1 = "大佬,".getBytes();
fos.write(bytes1);
// 往"a.txt"文件中追加寫入"你好!"內容
byte[] bytes2 = "你好!".getBytes();
fos.write(bytes2);
fos.close();
}
}
運行結果:生成了一個"a.txt"文件
如果需要換行:
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02OutputAppend {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("b.txt", true);
// 往"a.txt"文件中寫入"大佬,"內容
byte[] bytes1 = "大佬,".getBytes();
fos.write(bytes1);
// 換行 "\n" 或者 "\r"
byte[] bytes = "\n".getBytes();
fos.write(bytes);
// 往"a.txt"文件中追加寫入"你好!"內容
byte[] bytes2 = "你好!".getBytes();
fos.write(bytes2);
fos.close();
}
}
運行結果:生成了一個"b.txt"文件
字節輸入流 —— InputStream
java.io.InputStream抽象類是表示字節輸入流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。
public void close()
// 關閉此輸入流並釋放與此流相關聯的任何系統資源。
public abstract int read()
// 從輸入流讀取數據的下一個字節。
public int read(byte[] b)
// 從輸入流中讀取一些字節數,並將它們存儲到字節數組b中。
FileInputStream類
java.io.FileInputStream類是文件輸入流,從文件中讀取字節。
構造方法
public FileInputStream(String name) throws FileNotFoundException
// 通過打開與實際文件的連接來創建一個 FileInputStream,該文件由文件系統中的路徑名name命名。
public FileInputStream(File file) throws FileNotFoundException
// 通過打開與實際文件的連接來創建一個 FileInputStream,該文件由文件系統中的File對象file命名。
當我們創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出FileNotFoundException異常。
讀取數據的原理(硬盤-->內存):
Java程序 --> Java虛擬機 --> 操作系統 --> 操作系統調用讀取數據的方法 --> 讀取文件
字節輸入流的使用步驟
- 創建FileInputStream對象,構造方法中綁定要讀取的數據源。
- 使用FileInputStream對象中的方法read,讀取文件。
- 釋放資源。
下面這個例子中使用的read()方法是一個字節一個字節的讀取的。
import java.io.FileInputStream;
import java.io.IOException;
public class DemoInputRead {
public static void main(String[] args) throws IOException {
// 創建FileInputStream對象,構造方法中綁定要讀取的數據源
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/A");
// 使用FileInputStream對象中的方法read,讀取文件
// char=65 對應 A
int lien0 = fis.read();
char c0 = (char) lien0;
System.out.println(lien0 + "對應" + c0);
// char=10 對應 /n
int lien1 = fis.read();
char c1 = (char) lien1;
System.out.println(lien1 + "對應" + c1);
// char=66 對應 B
int lien2 = fis.read();
char c2 = (char) lien2;
System.out.println(lien2 + "對應" + c2);
// char=10 對應 /n
int lien3 = fis.read();
char c3 = (char) lien3;
System.out.println(lien3 + "對應" + c3);
// 釋放資源
fis.close();
}
}
文件A的內容:
如果已經將文件A的內容讀取完了,那么再讀取的話,會返回-1。
FileInputStream類中的部分方法
int available()
// 返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取(或跳過)的估計字節數。
void close()
// 關閉此輸入流並釋放與該流關聯的所有系統資源。
int read()
// 從輸入流中讀取數據的下一個字節。
int read(byte b[])
// 從輸入流中讀取一定數量的字節,並將其存儲在緩神區數組b中。
int read(byte b[], int off, int len)
// 將輸入流中最多len個數據字節讀入byte數組。
long skip(long n)
// 跳過和丟棄此輸入流中數據的n個字節。
read(byte b[])方法
import java.io.FileInputStream;
import java.io.IOException;
public class Demo02InputRead {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/B");
// 創建一個byte數組,存儲讀取的字節
byte[] bytes = new byte[2];
// 開始讀取,每次讀取兩個
// 第一次讀取: bytes = {97, 98},len1 = 2
int len1 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\t\t"
+ "len = " + len1
);
// 開始讀取,每次讀取兩個
// 第二次讀取: bytes = {99, 100},len2 = 2
int len2 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\t\t"
+ "len = " + len2
);
// 開始讀取,每次讀取兩個
// 第三次讀取: bytes = {101, 100},len3 = 2
int len3 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\t\t"
+ "len = " + len3
);
// 開始讀取,每次讀取兩個
// 第四次讀取: bytes = {101, 100},len4 = 2
int len4 = fis.read(bytes);
System.out.println(
"bytes = " + new String(bytes)
+ "\t\t"
+ "len = " + len4
);
}
}
文件B內容:
控制台輸出
bytes = ab len = 2
bytes = cd len = 2
bytes = ed len = 1
bytes = ed len = -1
解析:
第一次讀取:讀取第1個字節和第2個字節,將初始數組的{0, 0} 替換為 {a, b}
第二次讀取:讀取第3個字節和第4個字節,將第一次讀取后的數組的{a, b} 替換為 {c, d}
第三次讀取:讀取第5個字節,發現沒有可以讀取的了,於是將第二次讀取的數組的 {c, d}里面的c替換為e,而d沒得替換,即{e, d}
第四次讀取:因為第三次讀取的時候,已經讀取完了,沒有可以讀取的了,依舊還是原來的數組{e, d}
第一次讀取兩個字節(len1=2),第二次讀取兩個字節(len2=2),第三次讀取1個字節(len3=2),第四次沒得讀取(len4=-1)。
讀取完后,再讀取,返回值是-1。
字節流練習:圖片復制
文件復制的步驟:
- 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
- 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
- 使用字節輸入流對象中的方法read讀取文件。
- 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
- 釋放資源。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DemoCopyFile {
public static void main(String[] args) throws IOException {
// 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
// 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
// 使用字節輸入流對象中的方法read讀取文件。
int len = 0;
while ((len = fis.read()) != -1) {
// 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
fos.write(len);
}
// 釋放資源。先關閉寫的,再關閉讀的。
fis.close();
fos.close();
}
}
運行結果:
程序優化:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02CopyFile {
public static void main(String[] args) throws IOException {
// 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
// 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
// 使用字節輸入流對象中的方法read讀取文件。
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
// 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
fos.write(bytes, 0, len);
}
// 釋放資源。
fis.close();
fos.close();
}
}