大家好,我是IT修真院北京分院第27期的JAVA學員,一枚正直純潔善良的java程式員。
今天給大家分享一下,修真院官網Java任務10,深度思考中的知識點———什麼是IO流?
1.背景介紹
什麼是流
流就是一系列的資料
當不同的媒體之間有資料互動的時候,JAVA就使用流來實作。 資料源可以是檔案,還可以是資料庫,網絡甚至是其他的程式。 比如讀取檔案的資料到程式中,站在程式的角度來看,就叫做輸入流。 輸入流: InputStream 輸出流:OutputStream
檔案輸入流
如下代碼,就建立了一個檔案輸入流,這個流可以用來把資料從硬碟的檔案,讀取到JVM(記憶體)。 目前代碼隻是建立了流,還沒有開始讀取。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
File f = new File("d:/lol.txt");
// 建立基于檔案的輸入流
FileInputStream fis = new FileInputStream(f);
// 通過這個輸入流,就可以把資料從硬碟,讀取到Java的虛拟機中來,也就是讀取到記憶體中
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
--如圖:
标題
2.知識剖析
位元組流
InputStream位元組輸入流 OutputStream位元組輸出流 用于以位元組的形式讀取和寫入資料
ASCII碼 概念
所有的資料存放在計算機中都是以數字的形式存放的。 是以字母就需要轉換為數字才能夠存放。 比如A就對應的數字65,a對應的數字97. 不同的字母和符号對應不同的數字,就是一張碼表。 ASCII是這樣的一種碼表。 隻包含簡單的英文字母,符号,數字等。 不包含中文,德文,俄語等複雜的。
字元 | 十進制數字 | 十六進制數字 |
! | 33 | 21 |
" | 34 | 22 |
# | 35 | 23 |
$ | 36 | 24 |
% | 37 | 25 |
& | 38 | 26 |
' | 39 | 27 |
( | 40 | 28 |
) | 41 | 29 |
* | 42 | 2A |
+ | 43 | 2B |
, | 44 | 2C |
- | 45 | 2D |
. | 46 | 2E |
/ | 47 | 2F |
48 | 30 | |
1 | 49 | 31 |
2 | 50 | 32 |
3 | 51 | 33 |
4 | 52 | 34 |
5 | 53 | 35 |
6 | 54 | 36 |
7 | 55 | 37 |
8 | 56 | 38 |
9 | 57 | 39 |
: | 58 | 3A |
; | 59 | 3B |
< | 60 | 3C |
= | 61 | 3D |
> | 62 | 3E |
@ | 64 | 40 |
A | 65 | 41 |
B | 66 | 42 |
C | 67 | 43 |
D | 68 | 44 |
E | 69 | 45 |
F | 70 | 46 |
G | 71 | 47 |
H | 72 | 48 |
I | 73 | 49 |
J | 74 | 4A |
K | 75 | 4B |
L | 76 | 4C |
M | 77 | 4D |
N | 78 | 4E |
O | 79 | 4F |
P | 80 | 50 |
Q | 81 | 51 |
R | 82 | 52 |
S | 83 | 53 |
T | 84 | 54 |
U | 85 | 55 |
V | 86 | 56 |
W | 87 | 57 |
X | 88 | 58 |
Y | 89 | 59 |
Z | 90 | 5A |
[ | 91 | 5B |
\ | 92 | 5C |
] | 93 | 5D |
^ | 94 | 5E |
_ | 95 | 5F |
` | 96 | 60 |
a | 97 | 61 |
b | 98 | 62 |
c | 99 | 63 |
d | 100 | 64 |
e | 101 | 65 |
f | 102 | 66 |
g | 103 | 67 |
h | 104 | 68 |
i | 105 | 69 |
j | 106 | 6A |
k | 107 | 6B |
l | 108 | 6C |
m | 109 | 6D |
n | 110 | 6E |
o | 111 | 6F |
p | 112 | 70 |
q | 113 | 71 |
r | 114 | 72 |
s | 115 | 73 |
t | 116 | 74 |
u | 117 | 75 |
v | 118 | 76 |
w | 119 | 77 |
x | 120 | 78 |
y | 121 | 79 |
z | 122 | 7A |
{ | 123 | 7B |
| | 124 | 7C |
} | 125 | 7D |
~ | 126 | 7E |
--
以位元組流的形式讀取檔案内容
InputStream是位元組輸入流,同時也是抽象類,隻提供方法聲明,不提供方法的具體實作。 FileInputStream 是InputStream子類,以FileInputStream 為例進行檔案讀取
以位元組流的形式向檔案寫入資料
OutputStream是位元組輸出流,同時也是抽象類,隻提供方法聲明,不提供方法的具體實作。 FileOutputStream 是OutputStream子類,以FileOutputStream 為例向檔案寫出資料 注: 如果檔案d:/lol2.txt不存在,寫出操作會自動建立該檔案。 但是如果是檔案 d:/xyz/lol2.txt,而目錄xyz又不存在,會抛出異常
資料流
DataInputStream 資料輸入流 DataOutputStream 資料輸出流
直接進行字元串的讀寫
使用資料流的writeUTF()和readUTF() 可以進行資料的格式化順序讀寫 如本例,通過DataOutputStream 向檔案順序寫出 布爾值,整數和字元串。 然後再通過DataInputStream 順序讀入這些資料。 注: 要用DataInputStream 讀取一個檔案,這個檔案必須是由DataOutputStream 寫出的,否則會出現EOFException,因為DataOutputStream 在寫出的時候會做一些特殊标記,隻有DataInputStream 才能成功的讀取。
對象流
對象流指的是可以直接把一個對象以流的形式傳輸給其他的媒體,比如硬碟 一個對象以流的形式進行傳輸,叫做序列化。 該對象所對應的類,必須是實作Serializable接口
序列化一個對象
把一個對象序列化有一個前提是:這個對象的類,必須實作了Serializable接口
字元流
Reader字元輸入流 Writer字元輸出流 專門用于字元的形式讀取和寫入資料
使用字元流讀取檔案
FileReader 是Reader子類,以FileReader 為例進行檔案讀取
使用字元流把字元串寫入到檔案
FileWriter 是Writer的子類,以FileWriter 為例把字元串寫入到檔案
緩存流
以媒體是硬碟為例,位元組流和字元流的弊端: 在每一次讀寫的時候,都會通路硬碟。 如果讀寫的頻率比較高的時候,其性能表現不佳。 為了解決以上弊端,采用緩存流。 緩存流在讀取的時候,會一次性讀較多的資料到緩存中,以後每一次的讀取,都是在緩存中通路,直到緩存中的資料讀取完畢,再到硬碟中讀取。 就好比吃飯,不用緩存就是每吃一口都到鍋裡去鏟。用緩存就是先把飯盛到碗裡,碗裡的吃完了,再到鍋裡去鏟 緩存流在寫入資料的時候,會先把資料寫入到緩存區,直到緩存區達到一定的量,才把這些資料,一起寫入到硬碟中去。按照這種操作模式,就不會像位元組流,字元流那樣每寫一個位元組都通路硬碟,進而減少了IO操作。
使用緩存流讀取資料
緩存字元輸入流 BufferedReader 可以一次讀取一行數
使用緩存流寫出資料
PrintWriter 緩存字元輸出流, 可以一次寫出一行資料
FLUSH方法
有的時候,需要立即把資料寫入到硬碟,而不是等緩存滿了才寫出去。 這時候就需要用到flush
3.常見問題
如何關閉流
所有的流,無論是輸入流還是輸出流,使用完畢之後,都應該關閉。 如果不關閉,會産生對資源占用的浪費。 當量比較大的時候,會影響到業務的正常開展
4.解決方案
- 在try中關閉
在try的作用域裡關閉檔案輸入流,在前面的示例中都是使用這種方式,這樣做有一個弊端; 如果檔案不存在,或者讀取的時候出現問題而抛出異常,那麼就不會執行這一行關閉流的代碼,存在巨大的資源占用隐患。 不推薦使用
- 在finally中關閉
這是标準的關閉流的方式 1. 首先把流的引用聲明在try的外面,如果聲明在try裡面,其作用域無法抵達finally. 2. 在finally關閉之前,要先判斷該引用是否為空 3. 關閉的時候,需要再一次進行try catch處理 這是标準的嚴謹的關閉流的方式,但是看上去很繁瑣,是以寫不重要的或者測試代碼的時候,都會采用上面的有隐患try的方式,因為不麻煩
- 使用try()的方式
把流定義在try()裡,try,catch或者finally結束的時候,會自動關閉 這種編寫代碼的方式叫做 try-with-resources, 這是從JDK7開始支援的技術 所有的流,都實作了一個接口叫做 AutoCloseable,任何類實作了這個接口,都可以在try()中進行執行個體化。 并且在try, catch, finally結束的時候自動關閉,回收相關資源
5.編碼實戰
詳見視訊
https://v.qq.com/x/page/z0767my4wju.html?pcsharecode=VbuMUEue&sf=uri
6.擴充思考
SYSTEM.IN使用
System.out 是常用的在控制台輸出資料的 System.in 可以從控制台輸入資料
使用SYSTEM.IN.READ雖然可以讀取資料,但是很不友善。使用SCANNER就可以逐行讀取了
7. 參考文獻
how2j.cn: http://how2j.cn/k/io/io-system-in/352.html#nowhere
8. 更多讨論
Q1:io流的存儲位置和流向問題?
A1:IO流一般是以記憶體為基準,我們的IO流最開始是在jvm中,然後流向硬碟。
Q2:IO流傳輸時,是以檔案為機關傳輸,還是以檔案内位元組或字元依次傳輸?
A2:兩種情況都有,隻是進行檔案傳輸時候,會産生垃圾資料,锟斤拷
Q3:中文問題?
A3:工作後經常接觸的編碼方式有如下幾種:
ISO-8859-1 ASCII 數字和西歐字母
GBK GB2312 BIG5 中文
UNICODE (統一碼,萬國碼)
其中
ISO-8859-1 包含 ASCII
GB2312 是簡體中文,BIG5是繁體中文,GBK同時包含簡體和繁體以及日文。
UNICODE 包括了所有的文字,無論中文,英文,藏文,法文,世界所有的文字都包含其中
今天的分享就到這裡啦,歡迎大家點贊、轉發、留言、拍磚~