Java加強--2.IO流
- IO概述
- IO的分類
- 字節流
- 字符流
- 緩衝流
- 轉換流
- 序列化
- 打印流
- 關係圖
- 源碼
- 拓展
- Java加強--2.IO流
- IO概述
- IO的分類
- 字節流
- 字符流
- 緩衝流
- 轉換流
- 序列化
- 打印流
- 關係圖
- 源碼
- 拓展
- Java加強--2.IO流
IO概述
我們把這種數據的傳輸,可以看做是⼀種數據的流動,按照流動的⽅向,以內存爲基準,分爲 輸⼊
input 和 輸出output ,即流向內存是輸⼊流,流出內存的輸出流
Java中I/O操作主要是指使⽤ java.io 包下的內容,進⾏輸⼊、輸出操作。輸⼊也叫做讀取數據,輸
出也叫做作寫出數據
IO的分類
根據數據的流向分爲:輸⼊流和輸出流。
輸⼊流 :把數據從 其他設備 上讀取到 內存 中的流。
輸出流 :把數據從 內存 中寫出到 其他設備 上的流。
根據數據的類型分爲:字節流和字符流。
字節流 :以字節爲單位,讀寫數據的流。
字符流 :以字符爲單位,讀寫數據的流。
父類:
輸⼊流 | 輸出流 | |
---|---|---|
字節流 | 字節輸⼊流 InputStream | 字節輸出流OutputStream |
字符流 | 字符輸⼊流Reader | 字符輸出流Writer |
字節流
數據本質
⼀切⽂件數據(⽂本、圖⽚、視頻等)在存儲時,都是以⼆進制數字的形式保存,都⼀個⼀個的字節,
那麼傳輸時⼀樣如此。所以,字節流可以傳輸任意⽂件數據。在操作流的時候,我們要時刻明確,⽆
論使⽤什麼樣的流對象,底層傳輸的始終爲⼆進制數據。
任意類型的數據在計算機中都是以⼆進制形式存在。數據的本質就是⼆進制
字節輸出流【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字節,從偏移量 offff開始輸出到此輸出流
public abstract void write(int b) :將指定的字節輸出流
備註: close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileOutputStream類
java.io.FileOutputStream 類是⽂件輸出流,⽤於將數據寫出到⽂件
public FileOutputStream(File file) :創建⽂件輸出流以寫⼊由指定的 File對象表示的⽂件
public FileOutputStream(String name) : 創建⽂件輸出流以指定的名稱寫⼊⽂件
構造函數
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名創建流對象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
寫出字節: write(int b) ⽅法,每次可以寫出⼀個字節數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一個字節,ASCII十進制對應字符
os.write(97);
os.write(98);
os.write(99);
//關閉資源
os.close();
}
}
//a.txt文件中
abc
**備註:**流操作完畢後,必須釋放系統資源,調⽤close⽅法,千萬記得
寫出字節數組: write(byte[] b) ,每次可以寫出數組中的數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
好好學習,天天向上
write(byte[] b, int off, int len)
寫出指定⻓度字節數組: write(byte[] b, int off, int len) ,每次寫出從offff索引開始,len個字節
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組,從索引2開始,3個字節
os.write(bytes,6,3);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
//三個字節轉一個漢字,如果是中文,這裏要注意算3的倍數
學
數據追加續寫
public FileOutputStream(File file, boolean append) : 創建⽂件輸出流以寫⼊由指定的File對象表示的⽂件。
public FileOutputStream(String name, boolean append) : 創建⽂件輸出流以指定的名稱寫⼊⽂件。
這兩個構造⽅法,參數中都需要傳⼊⼀個boolean類型的值, true 表示追加數據, false 表示清空原有數據。這樣創建的輸出流對象,就可以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容
學好好學習,天天向上
換行
Windows系統⾥,換⾏符號是 \r\n 。把以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "已經換行".getBytes();
//換行
os.write("\r\n".getBytes());
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,包含之前(已換行)
學好好學習,天天向上
已經換行
回⻋符 \r 和換⾏符 \n :
回⻋符:回到⼀⾏的開頭(return)。
換⾏符:另起⼀⾏(newline)。
系統中的換⾏:
Windows系統⾥,每⾏結尾是 回⻋+換⾏ ,即 \r\n ;
Unix系統⾥,每⾏結尾只有 換⾏ ,即 \n ;
Mac系統⾥,每⾏結尾是 回⻋ ,即 \r 。從 Mac OS X開始與Linux統⼀。
字節輸⼊流【InputStream】
java.io.InputStream 抽象類是表示字節輸⼊流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此輸⼊流並釋放與此流相關聯的任何系統資源。
public abstract int read() : 從輸⼊流讀取數據的下⼀個字節。
public int read(byte[] b) : 從輸⼊流中讀取⼀些字節數,並將它們存儲到字節數組 b中 。
備註:close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileInputStream類
java.io.FileInputStream 類是⽂件輸⼊流,從⽂件中讀取字節
構造函數
FileInputStream(File file) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的 File對象 fifile命名。
FileInputStream(String name) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的路徑名 name命名。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。該路徑下,如果沒有該⽂件,會拋出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名稱創建流對象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字節: read (),每次可以讀取⼀個字節的數據,提升爲int類型,讀取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//讀取每一個字節數據,= -1 讀完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//釋放資源
fis.close();
}
}
//文件中內容:abcdefg
//輸出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字節數組讀取: read(byte[] b) ,每次讀取b的⻓度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
讀取有效字節
錯誤數據 j ,是由於最後⼀次讀取時,只讀取2個字節kl ,數組中,上次讀取的數據沒有被完全替換,所以要通過 len ,獲取有效的字節,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
當使⽤字節流讀取⽂本⽂件時,可能會有⼀個⼩問題。就是遇到中⽂字符時,可能不會顯示完整的字符,那是因爲⼀箇中⽂字符可能佔⽤多個字節存儲。所以Java提供⼀些字符流類,以字符爲單位讀寫數據,專⻔⽤於處理⽂本⽂件
字符輸⼊流【Reader】
java.io.Reader 抽象類是表示⽤於讀取字符流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此流並釋放與此流相關聯的任何系統資源。
public int read() : 從輸⼊流讀取⼀個字符。
public int read(char[] cbuf) : 從輸⼊流中讀取⼀些字符,並將它們存儲到字符數組 cbuf中 。
FileReader類
構造函數
FileReader(File file) : 創建⼀個新的 FileReader ,給定要讀取的File對象。
FileReader(String fileName) : 創建⼀個新的 FileReader ,給定要讀取的⽂件的名稱。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。類似於FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名稱創建流對象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字符: read ⽅法,每次可以讀取⼀個字符的數據,提升爲int類型,讀取到⽂件末尾,返
回 -1 ,循環讀取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int b;
// 循環讀取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 關閉資源
fr.close();
}
}
//文件文本
//abcdefg
//好好學習天天向上hijkl
//輸出
a
b
c
d
e
f
g
好
好
學
習
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符數組讀取: read(char[] cbuf) ,每次讀取b的⻓度個字符到數組中,返回讀取到的有
效字符個數,讀取到末尾時,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>ljk
讀取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>l
字符輸出流【Writer】
java.io.Writer 抽象類是表示⽤於寫出字符流的所有類的超類,將指定的字符信息寫出到⽬的地。它定義了字節輸出流的基本共性功能⽅法。
public abstract void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
public abstract void flush() :刷新緩衝區,將緩衝區中的數據輸出到⽬標⽂件中。
public void write(int b) :寫出⼀個字符。
public void write(char[] cbuf) :將 b.length字符從指定的字符數組寫出此輸出流。
public abstract void write(char[] b, int off, int len) :從指定的字符數組寫出 len字符,從偏移量 offff開始輸出到此輸出流。
public void write(String str) :寫出⼀個字符串。
FileWriter類
FileWriter(File file) : 創建⼀個新的 FileWriter,給定要讀取的File對象。
FileWriter(String fileName) : 創建⼀個新的 FileWriter,給定要讀取的⽂件的名稱。
構造函數
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名稱創建流對象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
寫出字符: write(int b) ⽅法,每次可以寫出⼀個字符數據
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件內容
aa好田
關閉與刷新
因爲內置緩衝區的原因,如果不關閉輸出流,⽆法寫出字符到⽂件中。但是關閉的流對象,是⽆法繼續寫出數據的。如果我們既想寫出數據,⼜想繼續使⽤流,就需要 flush ⽅法了。
flush :刷新緩衝區,流對象可以繼續使⽤。
close :關閉流,釋放系統資源。關閉前會刷新緩衝區,流對象不可以繼續使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件內容
aa好
//輸出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//輸出
好好學習,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//輸出
學習,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str);
fw.close();
}
}
//輸入
好好學習,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//輸出
習,天天
緩衝流
字節緩衝流
構造函數
public BufferedInputStream(InputStream in) :創建⼀個 新的緩衝輸⼊流。
public BufferedOutputStream(OutputStream out) : 創建⼀個新的緩衝輸出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
讀寫數據
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符緩衝流
構造函數
public BufferedReader(Reader in) :創建⼀個 新的緩衝輸⼊流。
public BufferedWriter(Writer out) : 創建⼀個新的緩衝輸出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 讀⼀⾏⽂字。
BufferedWriter: public void newLine() : 輸出⼀個換⾏符,由系統屬性定義符號
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**備註:**緩衝流比字節輸入流效率高很多;
轉換流
字符編碼:
計算機中儲存的信息都是⽤⼆進制數表示的,⽽我們在屏幕上看到的數字、英⽂、標點符號、漢字等
字符是⼆進制數轉換之後的結果。
按照某種規則,將字符存儲到計算機中,稱爲編碼 。
將存儲在計算機中的⼆進制數按照某種規則解析顯示出來,稱爲解碼 。
字符編碼 Character Encoding
字符編碼 Character Encoding : 就是⼀套⾃然語⾔的字符與⼆進制數之間的對應規則。
編碼表概述:
計算機存儲字符時將字符查詢碼錶,然後存儲對應的⼆進制。
計算機取出字符時將⼆進制查詢碼錶,然後轉換成對應的字符顯示。
ASCII:
* 美國碼錶,碼錶中只有英⽂⼤⼩寫字⺟、數字、美式標點符號等。每個字符佔⽤1個字節,所有字符映射的⼆進制都爲正數,因此有128個字符映射關係。
GB2312:
* 兼容ASCII碼錶,並加⼊了中⽂字符,碼錶中英⽂⼤⼩寫字⺟、數字、美式標點符號佔⼀個字節,中⽂佔兩個字節,中⽂映射的⼆進制都是負數,因此有128× 128 = 16384個字符映射關係。
GBK/GB18030:
* 兼容GB2312碼錶,英⽂⼤⼩寫字⺟、數字、美式標點符號,佔⼀個字節。中⽂佔兩個字節,第⼀個字節爲負數,第⼆個字節爲正數和負數,因爲有128× 256 = 32768個字符映射關係。
Unicode碼錶:
* 國際碼錶,包含各國⼤多數常⽤字符,每個字符都佔2個字節,因此有65536個字符映射關係。Java語⾔使⽤的就是Unicode碼錶。
* Java中的char類型⽤的就是這個碼錶。char c = 'a';佔兩個字節。
UTF-8碼錶:
* 是基於Unicode碼錶的,但更智能,會根據字符的內容選擇使⽤多個字節存儲。英⽂佔⼀個字節,中⽂佔3個字節。
亂碼的原因
* 因爲⽂本在存儲時使⽤的碼錶和讀取時使⽤的碼錶不⼀致造成的。
InputStreamReader類
構造函數
InputStreamReader(InputStream in) : 創建⼀個使⽤默認字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 創建⼀個指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換字符輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//創建一個指定編碼的轉換字符輸入流對象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
讀取數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//對於gbk編碼的文件輸入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter類
構造方法
OutputStreamWriter(OutputStream in) : 創建⼀個使⽤默認字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 創建⼀個指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個默認編碼的轉換字符輸出流對象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
寫出數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定編碼輸出字符,一個漢字佔2個字節
//utf-8,一個漢字佔3個字節
osw.write("你好");
osw.close();
}
}
序列化
概述
對象序列化概念
將對象轉換爲字節並保持到⽂件中的過程。
對象反序列化概念
將保持在⽂件中的字節讀取出來並轉換爲對象的過程。
序列化
java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到⽂件,實現對象的持久存儲。
滿足條件:
1.該類必須實現 java.io.Serializable 接⼝, Serializable 是⼀個標記接⼝,不實現此接⼝的類的對象在序列化過程中會拋出 NotSerializableException 。
構造函數
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "張三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 關鍵字作⽤
⽤來修飾成員變量的,能夠保證該成員變量的值不會被序列化到⽂件中
transient 使⽤格式
修飾符 transient 數據類型 變量名
反序列化
ObjectInputStream反序列化流,將之前使⽤ObjectOutputStream序列化的原始數據恢復爲對象。
構造方法
public ObjectInputStream(InputStream in) : 創建⼀個指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平時我們在控制檯打印輸出,是調⽤ print ⽅法和 println ⽅法完成的,這兩個⽅法都來⾃於 java.io.PrintStream 類,該類能夠⽅便地打印各種數據類型的值,是⼀種便捷的輸出⽅式。
PrintStream類
構造函數
public PrintStream(String fileName) : 使⽤指定的⽂件名創建⼀個新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
輸出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 設置系統的打印流流向,輸出到a.txt
System.setOut(ps);
//調用系統的打印流,再a.txt輸出97
System.out.println(97);
}
}
關係圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BX44YS3n-1592293192803)(E:\博客文檔\Java加強\img\IO1.jpg)]
源碼
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//構造函數
//用文件名創建字節輸入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File創建字節輸入流,主要創建函數
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//創建一個安全管理器
//在我們要測試一個未知的可能有風險的程序時需要開啓安全管理器,這樣保證這個未知程序啓動的時候不會損害到我們的系統
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//讀取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名構造函數
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名構造函數,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用這個文件,boolean 來創建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//調用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字節流的區別
字符流操作文件先經過緩衝區(內存)然後再通過緩衝區再操作文件
字節流操作文件不會經過緩衝區(內存直接操作文件本身)
緩衝區的作用
緩衝區就是一段特殊的內存區域,很多情況下當程序需要頻繁地操作一個資源(如文件或數據庫)則性能會很低,所以爲了提升性能就可以將一部分數據暫時讀寫到緩存區,以後直接從此區域中讀寫數據即可,這樣就顯著提升了性能
對於 Java 字符流的操作都是在緩衝區操作的,所以如果我們想在字符流操作中主動將緩衝區刷新到文件則可以使用 flush() 方法操作
字符流和字節流的選擇
**選擇字節流:**大多數時候 IO 操作都是直接操作磁盤文件,所以這些流在傳輸時都是以字節的方式進行的(圖片等都是按字節存儲的)
**選擇字符流:**通過 IO 在內存中頻繁處理字符串的情況使用字符流會好些,因爲字符流具備緩衝區,提高了性能
序列化及實現
序列化就是一種用來處理對象流的機制,將對象的內容進行流化。可以對流化後的對象進行讀寫操作,可以將流化後的對象傳輸於網絡之間。序列化是爲了解決在對象流讀寫操作時所引發的問題
將需要被序列化的類實現Serialize接口,沒有需要實現的方法,此接口只是爲了標註對象可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,再使用ObjectOutputStream對象的write(Object obj)方法就可以將參數obj的對象寫出
PrintStream/BufferedWriter/PrintWriter
PrintStream類的輸出功能非常強大,通常如果需要輸出文本內容,都應該將輸出流包裝成PrintStream後進行輸出。它還提供其他兩項功能。與其他輸出流不同,PrintStream 永遠不會拋出 IOException;
BufferedWriter類將文本寫入字符輸出流,緩衝各個字符從而提供單個字符,數組和字符串的高效寫入。通過write()方法可以將獲取到的字符輸出,然後通過newLine()進行換行操作。BufferedWriter中的字符流必須通過調用flush方法才能將其刷出去。並且BufferedWriter只能對字符流進行操作。
PrintWriter類的println方法自動添加換行,不會拋異常,若關心異常,需要調用checkError方法看是否有異常發生,PrintWriter構造方法可指定參數,實現自動刷新緩存(autoflush)
節點流/處理流定義及作用
節點流: 直接與數據源相連,用於輸入或者輸出(字節流)
**處理流:**在節點流的基礎上對之進行加工,進行一些功能的擴展; 處理流的構造器必須要傳入節點流的子類(字節緩衝流)
流的關閉及位置處理
流一旦打開就必須關閉,使用close方法;放入finally語句塊中(finally 語句一定會執行);多個流互相調用只關閉最外層的流
Java加強–2.IO流
IO概述
我們把這種數據的傳輸,可以看做是⼀種數據的流動,按照流動的⽅向,以內存爲基準,分爲 輸⼊
input 和 輸出output ,即流向內存是輸⼊流,流出內存的輸出流
Java中I/O操作主要是指使⽤ java.io 包下的內容,進⾏輸⼊、輸出操作。輸⼊也叫做讀取數據,輸
出也叫做作寫出數據
IO的分類
根據數據的流向分爲:輸⼊流和輸出流。
輸⼊流 :把數據從 其他設備 上讀取到 內存 中的流。
輸出流 :把數據從 內存 中寫出到 其他設備 上的流。
根據數據的類型分爲:字節流和字符流。
字節流 :以字節爲單位,讀寫數據的流。
字符流 :以字符爲單位,讀寫數據的流。
父類:
輸⼊流 | 輸出流 | |
---|---|---|
字節流 | 字節輸⼊流 InputStream | 字節輸出流OutputStream |
字符流 | 字符輸⼊流Reader | 字符輸出流Writer |
字節流
數據本質
⼀切⽂件數據(⽂本、圖⽚、視頻等)在存儲時,都是以⼆進制數字的形式保存,都⼀個⼀個的字節,
那麼傳輸時⼀樣如此。所以,字節流可以傳輸任意⽂件數據。在操作流的時候,我們要時刻明確,⽆
論使⽤什麼樣的流對象,底層傳輸的始終爲⼆進制數據。
任意類型的數據在計算機中都是以⼆進制形式存在。數據的本質就是⼆進制
字節輸出流【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字節,從偏移量 offff開始輸出到此輸出流
public abstract void write(int b) :將指定的字節輸出流
備註: close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileOutputStream類
java.io.FileOutputStream 類是⽂件輸出流,⽤於將數據寫出到⽂件
public FileOutputStream(File file) :創建⽂件輸出流以寫⼊由指定的 File對象表示的⽂件
public FileOutputStream(String name) : 創建⽂件輸出流以指定的名稱寫⼊⽂件
構造函數
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名創建流對象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
寫出字節: write(int b) ⽅法,每次可以寫出⼀個字節數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一個字節,ASCII十進制對應字符
os.write(97);
os.write(98);
os.write(99);
//關閉資源
os.close();
}
}
//a.txt文件中
abc
**備註:**流操作完畢後,必須釋放系統資源,調⽤close⽅法,千萬記得
寫出字節數組: write(byte[] b) ,每次可以寫出數組中的數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
好好學習,天天向上
write(byte[] b, int off, int len)
寫出指定⻓度字節數組: write(byte[] b, int off, int len) ,每次寫出從offff索引開始,len個字節
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組,從索引2開始,3個字節
os.write(bytes,6,3);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
//三個字節轉一個漢字,如果是中文,這裏要注意算3的倍數
學
數據追加續寫
public FileOutputStream(File file, boolean append) : 創建⽂件輸出流以寫⼊由指定的File對象表示的⽂件。
public FileOutputStream(String name, boolean append) : 創建⽂件輸出流以指定的名稱寫⼊⽂件。
這兩個構造⽅法,參數中都需要傳⼊⼀個boolean類型的值, true 表示追加數據, false 表示清空原有數據。這樣創建的輸出流對象,就可以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容
學好好學習,天天向上
換行
Windows系統⾥,換⾏符號是 \r\n 。把以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "已經換行".getBytes();
//換行
os.write("\r\n".getBytes());
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,包含之前(已換行)
學好好學習,天天向上
已經換行
回⻋符 \r 和換⾏符 \n :
回⻋符:回到⼀⾏的開頭(return)。
換⾏符:另起⼀⾏(newline)。
系統中的換⾏:
Windows系統⾥,每⾏結尾是 回⻋+換⾏ ,即 \r\n ;
Unix系統⾥,每⾏結尾只有 換⾏ ,即 \n ;
Mac系統⾥,每⾏結尾是 回⻋ ,即 \r 。從 Mac OS X開始與Linux統⼀。
字節輸⼊流【InputStream】
java.io.InputStream 抽象類是表示字節輸⼊流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此輸⼊流並釋放與此流相關聯的任何系統資源。
public abstract int read() : 從輸⼊流讀取數據的下⼀個字節。
public int read(byte[] b) : 從輸⼊流中讀取⼀些字節數,並將它們存儲到字節數組 b中 。
備註:close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileInputStream類
java.io.FileInputStream 類是⽂件輸⼊流,從⽂件中讀取字節
構造函數
FileInputStream(File file) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的 File對象 fifile命名。
FileInputStream(String name) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的路徑名 name命名。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。該路徑下,如果沒有該⽂件,會拋出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名稱創建流對象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字節: read (),每次可以讀取⼀個字節的數據,提升爲int類型,讀取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//讀取每一個字節數據,= -1 讀完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//釋放資源
fis.close();
}
}
//文件中內容:abcdefg
//輸出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字節數組讀取: read(byte[] b) ,每次讀取b的⻓度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
讀取有效字節
錯誤數據 j ,是由於最後⼀次讀取時,只讀取2個字節kl ,數組中,上次讀取的數據沒有被完全替換,所以要通過 len ,獲取有效的字節,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
當使⽤字節流讀取⽂本⽂件時,可能會有⼀個⼩問題。就是遇到中⽂字符時,可能不會顯示完整的字符,那是因爲⼀箇中⽂字符可能佔⽤多個字節存儲。所以Java提供⼀些字符流類,以字符爲單位讀寫數據,專⻔⽤於處理⽂本⽂件
字符輸⼊流【Reader】
java.io.Reader 抽象類是表示⽤於讀取字符流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此流並釋放與此流相關聯的任何系統資源。
public int read() : 從輸⼊流讀取⼀個字符。
public int read(char[] cbuf) : 從輸⼊流中讀取⼀些字符,並將它們存儲到字符數組 cbuf中 。
FileReader類
構造函數
FileReader(File file) : 創建⼀個新的 FileReader ,給定要讀取的File對象。
FileReader(String fileName) : 創建⼀個新的 FileReader ,給定要讀取的⽂件的名稱。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。類似於FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名稱創建流對象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字符: read ⽅法,每次可以讀取⼀個字符的數據,提升爲int類型,讀取到⽂件末尾,返
回 -1 ,循環讀取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int b;
// 循環讀取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 關閉資源
fr.close();
}
}
//文件文本
//abcdefg
//好好學習天天向上hijkl
//輸出
a
b
c
d
e
f
g
好
好
學
習
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符數組讀取: read(char[] cbuf) ,每次讀取b的⻓度個字符到數組中,返回讀取到的有
效字符個數,讀取到末尾時,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>ljk
讀取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>l
字符輸出流【Writer】
java.io.Writer 抽象類是表示⽤於寫出字符流的所有類的超類,將指定的字符信息寫出到⽬的地。它定義了字節輸出流的基本共性功能⽅法。
public abstract void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
public abstract void flush() :刷新緩衝區,將緩衝區中的數據輸出到⽬標⽂件中。
public void write(int b) :寫出⼀個字符。
public void write(char[] cbuf) :將 b.length字符從指定的字符數組寫出此輸出流。
public abstract void write(char[] b, int off, int len) :從指定的字符數組寫出 len字符,從偏移量 offff開始輸出到此輸出流。
public void write(String str) :寫出⼀個字符串。
FileWriter類
FileWriter(File file) : 創建⼀個新的 FileWriter,給定要讀取的File對象。
FileWriter(String fileName) : 創建⼀個新的 FileWriter,給定要讀取的⽂件的名稱。
構造函數
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名稱創建流對象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
寫出字符: write(int b) ⽅法,每次可以寫出⼀個字符數據
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件內容
aa好田
關閉與刷新
因爲內置緩衝區的原因,如果不關閉輸出流,⽆法寫出字符到⽂件中。但是關閉的流對象,是⽆法繼續寫出數據的。如果我們既想寫出數據,⼜想繼續使⽤流,就需要 flush ⽅法了。
flush :刷新緩衝區,流對象可以繼續使⽤。
close :關閉流,釋放系統資源。關閉前會刷新緩衝區,流對象不可以繼續使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件內容
aa好
//輸出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//輸出
好好學習,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//輸出
學習,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str);
fw.close();
}
}
//輸入
好好學習,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//輸出
習,天天
緩衝流
字節緩衝流
構造函數
public BufferedInputStream(InputStream in) :創建⼀個 新的緩衝輸⼊流。
public BufferedOutputStream(OutputStream out) : 創建⼀個新的緩衝輸出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
讀寫數據
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符緩衝流
構造函數
public BufferedReader(Reader in) :創建⼀個 新的緩衝輸⼊流。
public BufferedWriter(Writer out) : 創建⼀個新的緩衝輸出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 讀⼀⾏⽂字。
BufferedWriter: public void newLine() : 輸出⼀個換⾏符,由系統屬性定義符號
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**備註:**緩衝流比字節輸入流效率高很多;
轉換流
字符編碼:
計算機中儲存的信息都是⽤⼆進制數表示的,⽽我們在屏幕上看到的數字、英⽂、標點符號、漢字等
字符是⼆進制數轉換之後的結果。
按照某種規則,將字符存儲到計算機中,稱爲編碼 。
將存儲在計算機中的⼆進制數按照某種規則解析顯示出來,稱爲解碼 。
字符編碼 Character Encoding
字符編碼 Character Encoding : 就是⼀套⾃然語⾔的字符與⼆進制數之間的對應規則。
編碼表概述:
計算機存儲字符時將字符查詢碼錶,然後存儲對應的⼆進制。
計算機取出字符時將⼆進制查詢碼錶,然後轉換成對應的字符顯示。
ASCII:
* 美國碼錶,碼錶中只有英⽂⼤⼩寫字⺟、數字、美式標點符號等。每個字符佔⽤1個字節,所有字符映射的⼆進制都爲正數,因此有128個字符映射關係。
GB2312:
* 兼容ASCII碼錶,並加⼊了中⽂字符,碼錶中英⽂⼤⼩寫字⺟、數字、美式標點符號佔⼀個字節,中⽂佔兩個字節,中⽂映射的⼆進制都是負數,因此有128× 128 = 16384個字符映射關係。
GBK/GB18030:
* 兼容GB2312碼錶,英⽂⼤⼩寫字⺟、數字、美式標點符號,佔⼀個字節。中⽂佔兩個字節,第⼀個字節爲負數,第⼆個字節爲正數和負數,因爲有128× 256 = 32768個字符映射關係。
Unicode碼錶:
* 國際碼錶,包含各國⼤多數常⽤字符,每個字符都佔2個字節,因此有65536個字符映射關係。Java語⾔使⽤的就是Unicode碼錶。
* Java中的char類型⽤的就是這個碼錶。char c = 'a';佔兩個字節。
UTF-8碼錶:
* 是基於Unicode碼錶的,但更智能,會根據字符的內容選擇使⽤多個字節存儲。英⽂佔⼀個字節,中⽂佔3個字節。
亂碼的原因
* 因爲⽂本在存儲時使⽤的碼錶和讀取時使⽤的碼錶不⼀致造成的。
InputStreamReader類
構造函數
InputStreamReader(InputStream in) : 創建⼀個使⽤默認字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 創建⼀個指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換字符輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//創建一個指定編碼的轉換字符輸入流對象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
讀取數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//對於gbk編碼的文件輸入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter類
構造方法
OutputStreamWriter(OutputStream in) : 創建⼀個使⽤默認字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 創建⼀個指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個默認編碼的轉換字符輸出流對象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
寫出數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定編碼輸出字符,一個漢字佔2個字節
//utf-8,一個漢字佔3個字節
osw.write("你好");
osw.close();
}
}
序列化
概述
對象序列化概念
將對象轉換爲字節並保持到⽂件中的過程。
對象反序列化概念
將保持在⽂件中的字節讀取出來並轉換爲對象的過程。
序列化
java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到⽂件,實現對象的持久存儲。
滿足條件:
1.該類必須實現 java.io.Serializable 接⼝, Serializable 是⼀個標記接⼝,不實現此接⼝的類的對象在序列化過程中會拋出 NotSerializableException 。
構造函數
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "張三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 關鍵字作⽤
⽤來修飾成員變量的,能夠保證該成員變量的值不會被序列化到⽂件中
transient 使⽤格式
修飾符 transient 數據類型 變量名
反序列化
ObjectInputStream反序列化流,將之前使⽤ObjectOutputStream序列化的原始數據恢復爲對象。
構造方法
public ObjectInputStream(InputStream in) : 創建⼀個指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平時我們在控制檯打印輸出,是調⽤ print ⽅法和 println ⽅法完成的,這兩個⽅法都來⾃於 java.io.PrintStream 類,該類能夠⽅便地打印各種數據類型的值,是⼀種便捷的輸出⽅式。
PrintStream類
構造函數
public PrintStream(String fileName) : 使⽤指定的⽂件名創建⼀個新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
輸出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 設置系統的打印流流向,輸出到a.txt
System.setOut(ps);
//調用系統的打印流,再a.txt輸出97
System.out.println(97);
}
}
關係圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6asoYU7S-1592293193461)(E:\博客文檔\Java加強\img\IO1.jpg)]
源碼
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//構造函數
//用文件名創建字節輸入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File創建字節輸入流,主要創建函數
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//創建一個安全管理器
//在我們要測試一個未知的可能有風險的程序時需要開啓安全管理器,這樣保證這個未知程序啓動的時候不會損害到我們的系統
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//讀取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名構造函數
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名構造函數,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用這個文件,boolean 來創建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//調用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字節流的區別
字符流操作文件先經過緩衝區(內存)然後再通過緩衝區再操作文件
字節流操作文件不會經過緩衝區(內存直接操作文件本身)
緩衝區的作用
緩衝區就是一段特殊的內存區域,很多情況下當程序需要頻繁地操作一個資源(如文件或數據庫)則性能會很低,所以爲了提升性能就可以將一部分數據暫時讀寫到緩存區,以後直接從此區域中讀寫數據即可,這樣就顯著提升了性能
對於 Java 字符流的操作都是在緩衝區操作的,所以如果我們想在字符流操作中主動將緩衝區刷新到文件則可以使用 flush() 方法操作
字符流和字節流的選擇
**選擇字節流:**大多數時候 IO 操作都是直接操作磁盤文件,所以這些流在傳輸時都是以字節的方式進行的(圖片等都是按字節存儲的)
**選擇字符流:**通過 IO 在內存中頻繁處理字符串的情況使用字符流會好些,因爲字符流具備緩衝區,提高了性能
序列化及實現
序列化就是一種用來處理對象流的機制,將對象的內容進行流化。可以對流化後的對象進行讀寫操作,可以將流化後的對象傳輸於網絡之間。序列化是爲了解決在對象流讀寫操作時所引發的問題
將需要被序列化的類實現Serialize接口,沒有需要實現的方法,此接口只是爲了標註對象可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,再使用ObjectOutputStream對象的write(Object obj)方法就可以將參數obj的對象寫出
PrintStream/BufferedWriter/PrintWriter
PrintStream類的輸出功能非常強大,通常如果需要輸出文本內容,都應該將輸出流包裝成PrintStream後進行輸出。它還提供其他兩項功能。與其他輸出流不同,PrintStream 永遠不會拋出 IOException;
BufferedWriter類將文本寫入字符輸出流,緩衝各個字符從而提供單個字符,數組和字符串的高效寫入。通過write()方法可以將獲取到的字符輸出,然後通過newLine()進行換行操作。BufferedWriter中的字符流必須通過調用flush方法才能將其刷出去。並且BufferedWriter只能對字符流進行操作。
PrintWriter類的println方法自動添加換行,不會拋異常,若關心異常,需要調用checkError方法看是否有異常發生,PrintWriter構造方法可指定參數,實現自動刷新緩存(autoflush)
節點流/處理流定義及作用
節點流: 直接與數據源相連,用於輸入或者輸出(字節流)
**處理流:**在節點流的基礎上對之進行加工,進行一些功能的擴展; 處理流的構造器必須要傳入節點流的子類(字節緩衝流)
流的關閉及位置處理
流一旦打開就必須關閉,使用close方法;放入finally語句塊中(finally 語句一定會執行);多個流互相調用只關閉最外層的流
Java加強–2.IO流
IO概述
我們把這種數據的傳輸,可以看做是⼀種數據的流動,按照流動的⽅向,以內存爲基準,分爲 輸⼊
input 和 輸出output ,即流向內存是輸⼊流,流出內存的輸出流
Java中I/O操作主要是指使⽤ java.io 包下的內容,進⾏輸⼊、輸出操作。輸⼊也叫做讀取數據,輸
出也叫做作寫出數據
IO的分類
根據數據的流向分爲:輸⼊流和輸出流。
輸⼊流 :把數據從 其他設備 上讀取到 內存 中的流。
輸出流 :把數據從 內存 中寫出到 其他設備 上的流。
根據數據的類型分爲:字節流和字符流。
字節流 :以字節爲單位,讀寫數據的流。
字符流 :以字符爲單位,讀寫數據的流。
父類:
輸⼊流 | 輸出流 | |
---|---|---|
字節流 | 字節輸⼊流 InputStream | 字節輸出流OutputStream |
字符流 | 字符輸⼊流Reader | 字符輸出流Writer |
字節流
數據本質
⼀切⽂件數據(⽂本、圖⽚、視頻等)在存儲時,都是以⼆進制數字的形式保存,都⼀個⼀個的字節,
那麼傳輸時⼀樣如此。所以,字節流可以傳輸任意⽂件數據。在操作流的時候,我們要時刻明確,⽆
論使⽤什麼樣的流對象,底層傳輸的始終爲⼆進制數據。
任意類型的數據在計算機中都是以⼆進制形式存在。數據的本質就是⼆進制
字節輸出流【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字節,從偏移量 offff開始輸出到此輸出流
public abstract void write(int b) :將指定的字節輸出流
備註: close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileOutputStream類
java.io.FileOutputStream 類是⽂件輸出流,⽤於將數據寫出到⽂件
public FileOutputStream(File file) :創建⽂件輸出流以寫⼊由指定的 File對象表示的⽂件
public FileOutputStream(String name) : 創建⽂件輸出流以指定的名稱寫⼊⽂件
構造函數
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名創建流對象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
寫出字節: write(int b) ⽅法,每次可以寫出⼀個字節數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一個字節,ASCII十進制對應字符
os.write(97);
os.write(98);
os.write(99);
//關閉資源
os.close();
}
}
//a.txt文件中
abc
**備註:**流操作完畢後,必須釋放系統資源,調⽤close⽅法,千萬記得
寫出字節數組: write(byte[] b) ,每次可以寫出數組中的數據
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
好好學習,天天向上
write(byte[] b, int off, int len)
寫出指定⻓度字節數組: write(byte[] b, int off, int len) ,每次寫出從offff索引開始,len個字節
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組,從索引2開始,3個字節
os.write(bytes,6,3);
//關閉資源
os.close();
}
}
//文件內容,之前的被覆蓋掉了
//三個字節轉一個漢字,如果是中文,這裏要注意算3的倍數
學
數據追加續寫
public FileOutputStream(File file, boolean append) : 創建⽂件輸出流以寫⼊由指定的File對象表示的⽂件。
public FileOutputStream(String name, boolean append) : 創建⽂件輸出流以指定的名稱寫⼊⽂件。
這兩個構造⽅法,參數中都需要傳⼊⼀個boolean類型的值, true 表示追加數據, false 表示清空原有數據。這樣創建的輸出流對象,就可以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "好好學習,天天向上".getBytes();
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容
學好好學習,天天向上
換行
Windows系統⾥,換⾏符號是 \r\n 。把以指定是否追加續寫了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File對向創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串轉換爲字節數組
byte[] bytes = "已經換行".getBytes();
//換行
os.write("\r\n".getBytes());
//輸入字節數組
os.write(bytes);
//關閉資源
os.close();
}
}
//文件內容,包含之前(已換行)
學好好學習,天天向上
已經換行
回⻋符 \r 和換⾏符 \n :
回⻋符:回到⼀⾏的開頭(return)。
換⾏符:另起⼀⾏(newline)。
系統中的換⾏:
Windows系統⾥,每⾏結尾是 回⻋+換⾏ ,即 \r\n ;
Unix系統⾥,每⾏結尾只有 換⾏ ,即 \n ;
Mac系統⾥,每⾏結尾是 回⻋ ,即 \r 。從 Mac OS X開始與Linux統⼀。
字節輸⼊流【InputStream】
java.io.InputStream 抽象類是表示字節輸⼊流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此輸⼊流並釋放與此流相關聯的任何系統資源。
public abstract int read() : 從輸⼊流讀取數據的下⼀個字節。
public int read(byte[] b) : 從輸⼊流中讀取⼀些字節數,並將它們存儲到字節數組 b中 。
備註:close⽅法,當完成流的操作時,必須調⽤此⽅法,釋放系統資源
FileInputStream類
java.io.FileInputStream 類是⽂件輸⼊流,從⽂件中讀取字節
構造函數
FileInputStream(File file) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的 File對象 fifile命名。
FileInputStream(String name) : 通過打開與實際⽂件的連接來創建⼀個 FileInputStream ,該⽂件由⽂件系統中的路徑名 name命名。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。該路徑下,如果沒有該⽂件,會拋出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名稱創建流對象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字節: read (),每次可以讀取⼀個字節的數據,提升爲int類型,讀取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//讀取每一個字節數據,= -1 讀完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//釋放資源
fis.close();
}
}
//文件中內容:abcdefg
//輸出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字節數組讀取: read(byte[] b) ,每次讀取b的⻓度個字節到數組中,返回讀取到的有效字節個數,讀取到末尾時,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
讀取有效字節
錯誤數據 j ,是由於最後⼀次讀取時,只讀取2個字節kl ,數組中,上次讀取的數據沒有被完全替換,所以要通過 len ,獲取有效的字節,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字節個數
int len;
//定義讀取到的字節數組,作爲裝字節數據的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字節數組轉化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>學
3>>習
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
當使⽤字節流讀取⽂本⽂件時,可能會有⼀個⼩問題。就是遇到中⽂字符時,可能不會顯示完整的字符,那是因爲⼀箇中⽂字符可能佔⽤多個字節存儲。所以Java提供⼀些字符流類,以字符爲單位讀寫數據,專⻔⽤於處理⽂本⽂件
字符輸⼊流【Reader】
java.io.Reader 抽象類是表示⽤於讀取字符流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸⼊流的基本共性功能⽅法。
public void close() :關閉此流並釋放與此流相關聯的任何系統資源。
public int read() : 從輸⼊流讀取⼀個字符。
public int read(char[] cbuf) : 從輸⼊流中讀取⼀些字符,並將它們存儲到字符數組 cbuf中 。
FileReader類
構造函數
FileReader(File file) : 創建⼀個新的 FileReader ,給定要讀取的File對象。
FileReader(String fileName) : 創建⼀個新的 FileReader ,給定要讀取的⽂件的名稱。
當你創建⼀個流對象時,必須傳⼊⼀個⽂件路徑。類似於FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名稱創建流對象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
讀取字符: read ⽅法,每次可以讀取⼀個字符的數據,提升爲int類型,讀取到⽂件末尾,返
回 -1 ,循環讀取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int b;
// 循環讀取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 關閉資源
fr.close();
}
}
//文件文本
//abcdefg
//好好學習天天向上hijkl
//輸出
a
b
c
d
e
f
g
好
好
學
習
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符數組讀取: read(char[] cbuf) ,每次讀取b的⻓度個字符到數組中,返回讀取到的有
效字符個數,讀取到末尾時,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>ljk
讀取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定義變量,保存數據
int len;
char[] cbuf = new char[3];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 關閉資源
fr.close();
}
}
//原文
//abcdefg
//好好學習天天向上hijkl
//輸出
3>>abc
3>>def
3>>g
3>>好好學
3>>習天天
3>>向上h
3>>ijk
1>>l
字符輸出流【Writer】
java.io.Writer 抽象類是表示⽤於寫出字符流的所有類的超類,將指定的字符信息寫出到⽬的地。它定義了字節輸出流的基本共性功能⽅法。
public abstract void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
public abstract void flush() :刷新緩衝區,將緩衝區中的數據輸出到⽬標⽂件中。
public void write(int b) :寫出⼀個字符。
public void write(char[] cbuf) :將 b.length字符從指定的字符數組寫出此輸出流。
public abstract void write(char[] b, int off, int len) :從指定的字符數組寫出 len字符,從偏移量 offff開始輸出到此輸出流。
public void write(String str) :寫出⼀個字符串。
FileWriter類
FileWriter(File file) : 創建⼀個新的 FileWriter,給定要讀取的File對象。
FileWriter(String fileName) : 創建⼀個新的 FileWriter,給定要讀取的⽂件的名稱。
構造函數
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名稱創建流對象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
寫出字符: write(int b) ⽅法,每次可以寫出⼀個字符數據
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件內容
aa好田
關閉與刷新
因爲內置緩衝區的原因,如果不關閉輸出流,⽆法寫出字符到⽂件中。但是關閉的流對象,是⽆法繼續寫出數據的。如果我們既想寫出數據,⼜想繼續使⽤流,就需要 flush ⽅法了。
flush :刷新緩衝區,流對象可以繼續使⽤。
close :關閉流,釋放系統資源。關閉前會刷新緩衝區,流對象不可以繼續使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//寫一個字符
fw.write(97);
//第二個字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件內容
aa好
//輸出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//輸出
好好學習,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好學習,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//輸出
學習,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str);
fw.close();
}
}
//輸入
好好學習,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File對象創建流對象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好學習,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//輸出
習,天天
緩衝流
字節緩衝流
構造函數
public BufferedInputStream(InputStream in) :創建⼀個 新的緩衝輸⼊流。
public BufferedOutputStream(OutputStream out) : 創建⼀個新的緩衝輸出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
讀寫數據
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//創建字節緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//創建字節緩衝輸入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符緩衝流
構造函數
public BufferedReader(Reader in) :創建⼀個 新的緩衝輸⼊流。
public BufferedWriter(Writer out) : 創建⼀個新的緩衝輸出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 讀⼀⾏⽂字。
BufferedWriter: public void newLine() : 輸出⼀個換⾏符,由系統屬性定義符號
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//創建字符緩衝輸入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//創建字符緩衝輸入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**備註:**緩衝流比字節輸入流效率高很多;
轉換流
字符編碼:
計算機中儲存的信息都是⽤⼆進制數表示的,⽽我們在屏幕上看到的數字、英⽂、標點符號、漢字等
字符是⼆進制數轉換之後的結果。
按照某種規則,將字符存儲到計算機中,稱爲編碼 。
將存儲在計算機中的⼆進制數按照某種規則解析顯示出來,稱爲解碼 。
字符編碼 Character Encoding
字符編碼 Character Encoding : 就是⼀套⾃然語⾔的字符與⼆進制數之間的對應規則。
編碼表概述:
計算機存儲字符時將字符查詢碼錶,然後存儲對應的⼆進制。
計算機取出字符時將⼆進制查詢碼錶,然後轉換成對應的字符顯示。
ASCII:
* 美國碼錶,碼錶中只有英⽂⼤⼩寫字⺟、數字、美式標點符號等。每個字符佔⽤1個字節,所有字符映射的⼆進制都爲正數,因此有128個字符映射關係。
GB2312:
* 兼容ASCII碼錶,並加⼊了中⽂字符,碼錶中英⽂⼤⼩寫字⺟、數字、美式標點符號佔⼀個字節,中⽂佔兩個字節,中⽂映射的⼆進制都是負數,因此有128× 128 = 16384個字符映射關係。
GBK/GB18030:
* 兼容GB2312碼錶,英⽂⼤⼩寫字⺟、數字、美式標點符號,佔⼀個字節。中⽂佔兩個字節,第⼀個字節爲負數,第⼆個字節爲正數和負數,因爲有128× 256 = 32768個字符映射關係。
Unicode碼錶:
* 國際碼錶,包含各國⼤多數常⽤字符,每個字符都佔2個字節,因此有65536個字符映射關係。Java語⾔使⽤的就是Unicode碼錶。
* Java中的char類型⽤的就是這個碼錶。char c = 'a';佔兩個字節。
UTF-8碼錶:
* 是基於Unicode碼錶的,但更智能,會根據字符的內容選擇使⽤多個字節存儲。英⽂佔⼀個字節,中⽂佔3個字節。
亂碼的原因
* 因爲⽂本在存儲時使⽤的碼錶和讀取時使⽤的碼錶不⼀致造成的。
InputStreamReader類
構造函數
InputStreamReader(InputStream in) : 創建⼀個使⽤默認字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 創建⼀個指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換字符輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//創建一個指定編碼的轉換字符輸入流對象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
讀取數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//創建一個默認編碼的轉換輸入流對象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//對於gbk編碼的文件輸入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter類
構造方法
OutputStreamWriter(OutputStream in) : 創建⼀個使⽤默認字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 創建⼀個指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個默認編碼的轉換字符輸出流對象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
寫出數據
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個指定編碼的轉換字符輸出流對象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定編碼輸出字符,一個漢字佔2個字節
//utf-8,一個漢字佔3個字節
osw.write("你好");
osw.close();
}
}
序列化
概述
對象序列化概念
將對象轉換爲字節並保持到⽂件中的過程。
對象反序列化概念
將保持在⽂件中的字節讀取出來並轉換爲對象的過程。
序列化
java.io.ObjectOutputStream 類,將Java對象的原始數據類型寫出到⽂件,實現對象的持久存儲。
滿足條件:
1.該類必須實現 java.io.Serializable 接⼝, Serializable 是⼀個標記接⼝,不實現此接⼝的類的對象在序列化過程中會拋出 NotSerializableException 。
構造函數
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "張三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//創建一個序列化輸出對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 關鍵字作⽤
⽤來修飾成員變量的,能夠保證該成員變量的值不會被序列化到⽂件中
transient 使⽤格式
修飾符 transient 數據類型 變量名
反序列化
ObjectInputStream反序列化流,將之前使⽤ObjectOutputStream序列化的原始數據恢復爲對象。
構造方法
public ObjectInputStream(InputStream in) : 創建⼀個指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//創建一個序列化輸出對象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平時我們在控制檯打印輸出,是調⽤ print ⽅法和 println ⽅法完成的,這兩個⽅法都來⾃於 java.io.PrintStream 類,該類能夠⽅便地打印各種數據類型的值,是⼀種便捷的輸出⽅式。
PrintStream類
構造函數
public PrintStream(String fileName) : 使⽤指定的⽂件名創建⼀個新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
輸出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 設置系統的打印流流向,輸出到a.txt
System.setOut(ps);
//調用系統的打印流,再a.txt輸出97
System.out.println(97);
}
}
關係圖
源碼
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//構造函數
//用文件名創建字節輸入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File創建字節輸入流,主要創建函數
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//創建一個安全管理器
//在我們要測試一個未知的可能有風險的程序時需要開啓安全管理器,這樣保證這個未知程序啓動的時候不會損害到我們的系統
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//讀取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名構造函數
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名構造函數,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用這個文件,boolean 來創建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//調用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字節流的區別
字符流操作文件先經過緩衝區(內存)然後再通過緩衝區再操作文件
字節流操作文件不會經過緩衝區(內存直接操作文件本身)
緩衝區的作用
緩衝區就是一段特殊的內存區域,很多情況下當程序需要頻繁地操作一個資源(如文件或數據庫)則性能會很低,所以爲了提升性能就可以將一部分數據暫時讀寫到緩存區,以後直接從此區域中讀寫數據即可,這樣就顯著提升了性能
對於 Java 字符流的操作都是在緩衝區操作的,所以如果我們想在字符流操作中主動將緩衝區刷新到文件則可以使用 flush() 方法操作
字符流和字節流的選擇
**選擇字節流:**大多數時候 IO 操作都是直接操作磁盤文件,所以這些流在傳輸時都是以字節的方式進行的(圖片等都是按字節存儲的)
**選擇字符流:**通過 IO 在內存中頻繁處理字符串的情況使用字符流會好些,因爲字符流具備緩衝區,提高了性能
序列化及實現
序列化就是一種用來處理對象流的機制,將對象的內容進行流化。可以對流化後的對象進行讀寫操作,可以將流化後的對象傳輸於網絡之間。序列化是爲了解決在對象流讀寫操作時所引發的問題
將需要被序列化的類實現Serialize接口,沒有需要實現的方法,此接口只是爲了標註對象可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,再使用ObjectOutputStream對象的write(Object obj)方法就可以將參數obj的對象寫出
PrintStream/BufferedWriter/PrintWriter
PrintStream類的輸出功能非常強大,通常如果需要輸出文本內容,都應該將輸出流包裝成PrintStream後進行輸出。它還提供其他兩項功能。與其他輸出流不同,PrintStream 永遠不會拋出 IOException;
BufferedWriter類將文本寫入字符輸出流,緩衝各個字符從而提供單個字符,數組和字符串的高效寫入。通過write()方法可以將獲取到的字符輸出,然後通過newLine()進行換行操作。BufferedWriter中的字符流必須通過調用flush方法才能將其刷出去。並且BufferedWriter只能對字符流進行操作。
PrintWriter類的println方法自動添加換行,不會拋異常,若關心異常,需要調用checkError方法看是否有異常發生,PrintWriter構造方法可指定參數,實現自動刷新緩存(autoflush)
節點流/處理流定義及作用
節點流: 直接與數據源相連,用於輸入或者輸出(字節流)
**處理流:**在節點流的基礎上對之進行加工,進行一些功能的擴展; 處理流的構造器必須要傳入節點流的子類(字節緩衝流)
流的關閉及位置處理
流一旦打開就必須關閉,使用close方法;放入finally語句塊中(finally 語句一定會執行);多個流互相調用只關閉最外層的流