網站首頁 編程語言 正文
IO流
1.流的概念和分類
-
IO流核心組成
- 核心組成:一個類(File)、一個接口(Serializable)、四個抽象類(InputStream/OutputStream、Reader/Writer)
-
什么是流
- 流:內存與存儲設備之間傳輸數據的通道
-
流的分類
-
按方向
- 輸入流:將<存儲設備>中的內容讀到<內存>中
- 輸出流:將<內存>中的內容寫到<存儲設備>中
-
按單位
- 字節流:以字節為單位,可以讀寫所有數據
- 字符流:以字符為單位,只能讀寫文本數據
-
按功能
- 節點流:具有實際傳輸數據的讀寫功能
- 過濾流:在節點流的基礎之上增強功能
2.字節流
2.1字節流抽象類
-
InputStream
- 此抽象類是表示字節輸入流的所有類的父類。InputSteam是一個抽象類,它不可以實例化。數據的讀取需要由它的子類來實現。根據節點的不同,它派生了不同的節點流子類。
- 繼承自InputSteam的流都是用于向程序中輸入數據,且數據的單位為字節(8 bit)
-
常用方法:
public int read(){}
:讀取一個字節的數據,并將字節的值作為int類型返回(0-255之間的一個值)。如果未讀出字節則返回-1(返回值為-1表示讀取結束)。while((data=fis.read())!=-1)來判斷讀取文件是否結束。public int read(byte[] b){}
:從該輸入流讀取最多 b.length個字節的數據,并把讀取的數據存放到b這個字符數組里面public int read(byte[] b, int off, int len){}
-
OutputStream
-
此抽象類是表示字節輸出流的所有類的父類。輸出流接收輸出字節并將這些字節發送到某個目的地
public void write(int n)
:向目的地中寫入一個字節public void write(byte[] b){}
: 將 b.length個字節從指定的字節數組寫入此文件輸出流。public void write(byte[] b, int off, int len){}
-
此抽象類是表示字節輸出流的所有類的父類。輸出流接收輸出字節并將這些字節發送到某個目的地
2.2文件字節流
-
FileInputStream:
- public int read(byte[] b) // 從流中讀取多個字節,將讀到內容存入 b 數組,返回實際讀到的字節數;如果達到文件的尾部,則返回 -1
-
FileOutputStream:
- public void write(byte[] b) // 一次寫多個字節,將 b 數組中所有字節,寫入輸出流
2.21 文件字節輸入流代碼演示
package stream.demo01;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
FileInputStream 使用
文件字節輸入流
*/
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
// 1 創建FileInputStream 并指定文件路徑
FileInputStream fileInputStream = new FileInputStream("D:\\atext.txt");
// 2 讀取文件
/*
// 方式一:單字節讀取
int date=0;
//int d1 = fileInputStream.read(); 不可以在這里賦值給d1,不然就只是讀了一個字節
//必須加括號,不然不知道執行誰
while ((date=fileInputStream.read())!=-1){
System.out.print((char) date);
}
*/
// 方式二:一次讀取多個字節(3)
byte[] array=new byte[3];// 大小為3的緩存區
/*
int count = fileInputStream.read(array);
//System.out.println((new String(array)));// 一次讀3個
String s = new String(array);
System.out.println(s);
int count2 = fileInputStream.read(array);
System.out.println(new String(array));// 再讀3個
int count3=fileInputStream.read(array);
System.out.println(new String(array));
*/
// 上述優化后
int count=0;
//返回讀取到了多少個元素,如果沒有讀取到返回-1
while ((count=fileInputStream.read(array))!=-1){
System.out.println(new String(array,0,count)); // new String(bytes, 0, count) 轉換字符串從bytes的0下標開始,讀count個字符串
}
// 3 關閉
fileInputStream.close();
System.out.println();
System.out.println("執行完畢");
}
}
運行結果
abc
def
gha
bcd
efg
hab
cde
fga
bcd
efg
hab
cde
fgh
abc
def
ghh
abc
def
gha
bcd
efg
h
執行完畢
2.22 文件字節輸出流代碼演示
package stream.demo01;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
文件輸出流的使用
FileOutputStream
*/
public class FileOutputStreamTest {
public static void main(String[] args) throws IOException {
// 1 創建文件字節輸出流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\fff.txt",true);// true表示不覆蓋 接著寫
/*
// 2 寫入文件
fileOutputStream.write(97);
fileOutputStream.write('b');
fileOutputStream.write('c');
fileOutputStream.write('d');
fileOutputStream.write('e');
*/
byte[] bytes = new byte[10];
String st="hello world";
fileOutputStream.write(st.getBytes());//getBytes():獲取字節數據
//getBytes(String charsetName):使用指定的字符集將字符串編碼為byte序列,并將結果存儲到一個新的byte數組中
// 3 關閉
fileOutputStream.close();
System.out.println("復制完成");
}
}
運行結果
復制完成
2.23 文件字節流復制文件代碼演示
package stream.demo01;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
//使用字節流實現文件的復制
public class StreamCopyTest {
public static void main(String[] args) throws IOException {
// 1 創建流
// 1.1 文件字節輸入流
FileInputStream fis = new FileInputStream("D:\\a50.jpg");
// 1.2 文件字節輸出流
FileOutputStream fos = new FileOutputStream("D:\\b50.jpg");
// 2 邊讀邊寫
byte[] bytes = new byte[1024*5];
int count=0;
while ((count=fis.read(bytes))!=-1){
fos.write(bytes,0,count);
}
// 3 關閉
fis.close();
fos.close();
System.out.println("執行完畢");
}
}
運行結果
執行完畢
2.3 字節緩沖流
-
緩沖流:BufferedInputStream/ BufferedOutputStream
- 提高IO效率,減少訪問磁盤次數
- 數據存儲在緩沖區中,flush是將緩沖區的內容寫入文件中,也可以直接close
2.31 字節緩沖輸入流代碼演示:
package stream.demo01;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
// 字節緩沖流輸入流
public class BufferedInputStreamTest {
public static void main(String[] args) throws Exception {
// 1 創建BufferedInputStream
FileInputStream fis = new FileInputStream("D:\\atext.txt");
BufferedInputStream bis = new BufferedInputStream(fis);// 目的是增強底層流的功能, 先讀到緩沖區
//創建字節緩沖流對象時需要向其輸入一個底層流
/*
// 2 讀取
int count=0;
while ((count=bis.read())!=-1){
System.out.print((char)count);
}
*/
// 用自己創建的緩沖流
byte[] bytes = new byte[1024 * 5];
int count=0;
while ((count=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,count));
}
// 3 關閉
bis.close();
}
}
運行結果
abcdefghabcdefghabcdefgabcdefghabcdefghabcdefghhabcdefghabcdefgh
2.32 字節緩沖輸出流代碼演示:
package stream.demo01;
import java.io.*;
// 使用字節緩沖流 寫入 文件
public class BufferedOutputStreamTest {
public static void main(String[] args) throws IOException {
// 1 創建BufferedInputStream
FileOutputStream fis = new FileOutputStream("D:\\buffer.txt");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fis);
// 2 寫入文件
for (int i = 0; i < 10; i++) {// 此時讀到了緩沖區,沒有在文件中
bufferedOutputStream.write("hello world\r\n".getBytes());//\r\n 轉義字符換行打印
}
System.out.println("執行完畢");
// 3 關閉 bos.flush(); // 刷新到硬盤 close方法里自帶有
bufferedOutputStream.close();
}
}
運行結果
執行完畢
2.4 對象流
-
ObjectInputStream/ObiectOutputStream
-
增強了緩沖區功能
-
增強了讀寫 8 種基本數據類型和字符串功能
-
增強了讀寫對象的功能
readObject()
從流中讀取一個對象writeObject(Object obj)
向流中寫入一個對象 -
使用流傳輸對象的過程稱為序列化、反序列化
-
-
序列化對象類的書寫注意事項
- 序列化類必須實現 Serializable 接口
- 序列化類中的對象屬性要實現 Serializable 接口
-
序列化版本號ID,保證序列化的類和反序列化的類是同一個類
private static final long serialVersionUID = 100L;
- 使用transient修飾屬性,這個屬性就不能序列化
- 靜態屬性不能序列化
- 序列化多個對象,可以借助集合來實現
2.41 序列化代碼演示:
package stream.demo01;
import java.io.Serializable;
public class Student implements Serializable {
//類要想序列化必須實現Serializable接口
private String name;
// private int age;
private transient int age; //Student{name='zhangsan', age=0}
//使用transient修飾屬性,使屬性不能被序列化
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package stream.demo01;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
// 使用objectoutputStream實現對象的序列化
//注意:在寫對象這個類的時候需要public class Student implements Serializable實現這個接口。
/*
1.某個類要想序列化必須實現Serializable接口
2.序列化類中對象屬性要求實現Serializable接口
3.序列化版本號ID,保證序列化的類和反序列化的類是同一個類
4.使用transient修飾屬性,這個屬性就不能序列化
5.靜態屬性不能序列化
6.序列化多個對象,可以借助集合來實現
*/
public class ObjectOutputStreamTest {
public static void main(String[] args) throws IOException {
// 1. 創建對象流
FileOutputStream fos = new FileOutputStream("D:\\student.bin");//這里文件類型可以隨便寫,但是和反序列化一定要一致
ObjectOutputStream obj = new ObjectOutputStream(fos); //bin表示這是一個二進制文件類型
// 2. 序列化(寫入操作)
Student s = new Student("zhangsan",18);
Student lisi = new Student("lisi", 20);
ArrayList<Student> Arry=new ArrayList<>();
Arry.add(s);
Arry.add(lisi);
obj.writeObject(Arry);
// obj.writeObject(s);
// obj.writeObject(lisi);
// 3. 關閉
obj.close();
System.out.println("序列化執行完畢");
}
}
運行結果
序列化執行完畢
2.42 反序列化代碼演示:
package stream.demo01;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Objects;
// 使用ObjectInputSteam實現反序列化(讀取重構對象)
//反序列化(重構成對象)
public class ObjectInputStreamTest {
public static <ArrrayList> void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 創建對象流
FileInputStream fis = new FileInputStream("D:\\student.bin");
ObjectInputStream obs = new ObjectInputStream(fis);
// 2. 讀取文件(反序列化)
// Student s = (Student) obs.readObject(); //readObject() 返回類型為Object,因此需要強轉
// Student o = (Student)obs.readObject();
ArrayList<Student> objects=(ArrayList<Student>) obs.readObject();
// 3. 關閉
obs.close();
System.out.println("反序列化執行完畢");
// System.out.println(s.toString());
// System.out.println(o.toString());
System.out.println(objects.toString());
}
}
運行結果
反序列化執行完畢
[Student{name='zhangsan', age=0}, Student{name='lisi', age=0}]
3.編碼方式(常見字符形式)
-
引言
- 在計算機中提供給用戶最常見的顯示就是字符,也稱之為文本,字符的種類非常多,每種語言都有自己的字符集,那么,這么多的字符,如何存儲進計算機中呢?
-
計算機存儲字符的本質原理
- 每個字符都通過字符集的映射轉化為一個整數存儲在計算機中,所以存儲字符的本質還是存儲整數。
- 將字符轉為對應碼值,然后將碼值轉換為二進制,最后存到計算機中。
3.1 常用編碼介紹
-
采用不同的編碼方式,則字符對應的碼值就不同。目前常見的編碼方式有:
- ASCII碼。固定使用1個字節來表示字符,可以表示128個字符
- Unicode碼。固定使用2個字節來表示字符(字母和漢字都是)。
- utf-8。字母用1個字節表示,漢字用3個字節表示。
- GBK。字母用1個字節表示,漢字用2個字節表示。
3.2 各編碼詳細介紹
-
英文字符集 —— ASCII
-
上個世紀60年代,美國制定了一套字符編碼,對英語字符與二進制位之間的關系做了統一規定,這一規定被稱為 ASCII 碼
-
ASCII ((American Standard Code for Information Interchange): 美國信息交換標準代碼
-
ASCII 碼規定使用一個字節來存儲英文字符,最前面的一位統一規定為0,不同的字符由后面的7位確定, 所以ASCII碼一共規定了128個字符的編碼
-
【優點】只用1個字節表示字符
-
【缺點】最多只表示127個字符,表示字符數量有限。
-
-
全世界的字符集 —— Unicode
-
全世界的語言非常多,每種語言都有自己的字符集,非常的不方便,并且極其容易出現亂碼,所以Unicode字符集的誕生就是為了將世界上所有的字符都納入其中,形成一種統一的編碼規定。
-
Unicode,統一碼,又叫萬國碼。
-
Unicode只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲
-
【優點】不會出現亂碼現象
-
【缺點】固定使用2個字節表示一個字符(包括字母、漢字),比較占用存儲空間。
-
-
UTF-8編碼
-
UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是針對Unicode的一種可變長度字符編碼。(可以理解為是對Unicode編碼的改進)
-
它可以用來表示Unicode編碼中的任何字符,而且其編碼中的第一個字節仍與ASCII相容(即同樣向下兼容ASCII編碼),使得原來處理ASCII字符的軟件無須或只進行少部分修改后,便可繼續使用。因此,它逐漸成為電子郵件、網頁及其他存儲或傳送文字的應用中,優先采用的編碼。
-
【特點】字母用1個字節表示,漢字用3個字節。
-
-
中文字符集 —— GBK
- 中華文明源遠流長,目前漢字大約有十萬個,常用的漢字都有幾千個,這么多的字符,顯然靠美國的ASCII碼字符集是不可能存儲的
- 國家標準化委員于1995年頒布了GBK標準,全稱“漢字編碼擴展規范”,GBK兼容GB2312標準,同時在GB2312標準的基礎上擴展了GB13000包含的字,但編碼不同
- GBK標準中收錄了2萬多漢字及符號,因其最早被WINDOWS采用,所以其應用范圍非常廣
————————————————————————————————————————————————————————————————————————————
更多參考
千峰教育-IO框架
字符在計算機中的存儲
Java計算機如何存儲字符&&常用編碼介紹
原文鏈接:https://blog.csdn.net/qq_60501861/article/details/125627734
相關推薦
- 2022-08-02 python生產環境禁用assert斷言的方法_python
- 2021-12-13 C++繼承類成員訪問權限修飾符詳解_C 語言
- 2023-01-19 Go定時器的三種實現方式示例詳解_Golang
- 2023-04-03 Python數據結構棧實現進制轉換簡單示例_python
- 2022-07-14 浮點數乘法和整形乘除法的效率經驗比較_C 語言
- 2022-10-04 一文教會你用Python讀取PDF文件_python
- 2021-12-11 Docker容器編譯LNMP的實現示例_docker
- 2022-04-12 網絡編程——Http請求方式Get與Post
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支