道阻且長,行則將至。埋頭苦幹,不鳴則已,一鳴驚人!加油,騷年!
目錄及資源索引
1 什麼是I/O?
從字面意思理解也很簡單,其實就是輸入(input)輸出(output)首字母的縮寫。CPU 與外部設備、存儲器的連接和數據交換都需要通過接口設備來實現,前者稱爲 I/O 接口,而後者則稱爲存儲器接口。
I/O 設備品種繁多,相應的接口電路也各不相同,因此,我們習慣上說的接口,只是指 I/O 接口。
Java 中的 I/O 操作是通過輸入/輸出數據流的形式來完成的,因此它也稱作數據流操作。通俗地講,這實際上就是一種數據的輸入輸出方式。
I/O 操作的目標:從數據源當中讀取數據,以及將數據寫入到數據目的地當中。
2 I/O的流向
既然 I/O 操作實際是數據的輸入輸出方式,那就肯定涉及到一個方向問題,需要一個參照物,並且流向的意義很重要。
- 輸入:將數據源讀取到程序中,就是輸入;
- 輸出:需要將程序中的內容,寫入到網絡,其他文件等,就是輸出;
問:輸入輸出爲什麼叫流?
答:stream 有流動的意思,可以把流看成一個管道,所謂流,就是在數據源與程序之間建立一個數據流淌的管道,數據不是一下就全到程序中去,而是需要慢慢的傳輸;
3 I/O的分類
按照老師的講解,大致有三種分類方法
- 第一種分法
- 輸入流;
- 輸出流
- 第二種分法
- 字節流
- 字符流
- 第三種分法
- 節點流
- 處理流
字節流:以字節爲基礎;
字符流:是以字符爲基礎;每次讀寫,都是一個或者幾個字符;
節點流:真正處理數據的I/O流;
處理流:在節點流基礎上對數據再加工。(例如:水管外,加熱,磁化等)
本節主要學習字節流
4 字節流的核心類
InputStream
與 OutputStream
是所有的 字節流 的父類;即所有的字節流都是這兩個的子類。
核心類提供的核心方法如下:
// InputStream
int read(byte[] b, int off, int len)
// OutputStream
void write(byte[] b, int off, itn len)
我剛開始不是學 Java 的,看到 byte[] b
這種形式,很是懵逼,後來查了一下發現,只是寫法不太一樣,最終效果還是一樣的,就是定義了一個類型爲 byte 的數組名爲 b 的數組,大小不確定,而已…,要是按照 C/C++ 中的寫法,應該是 byte b[]
,其實沒啥差別。。。
先說輸入流的 read 函數
- byte[] b:就是一個 byte 類型的數組;
- off:偏移量,就是從數組的第幾位開始寫;
- len:讀取一次,最多讀多少數據;(感覺跟喝一杯水一樣,一口最多喝多少…)
- 返回值:這次總共讀取了多少個數據
然後是輸出流的 write 函數
- byte[] b:要寫進去的數據;
- off:偏移量,從 byte 數組的第 off 位開始,往後的才寫到文件中去,前邊的不要了;
- len:這一次總共要往文件中寫入多少個數據;
實際演示代碼如下:
import java.io.*; // 導入類
class Test
{
public static void main(String args[])
{
FileInputStream fis = null;
try
{
fis = new FileInputStream("from.txt");
byte [] buffer = new byte[100];
fis.read(buffer, 0, buffer.length);
for(int i = 0; i < buffer.length; i++)
{
System.out.println(buffer[i]);
}
}
catch(Exception e)
{
System.out.println(e);
}
}
}
其中 from.txt 中的內容爲 abcd ,則上述代碼運行後的結果如下:
由上述運行結果可以看到,把 abcd 這幾個字母的 ASCII 碼全部打印出來了,後邊沒有的默認填0,爲什麼呢?因爲 buffer.length 是數組的長度,也就是我一次能讀100個,結果你只給我4個,那剩下96個就默認填寫0了。
如果要測試一下偏移量,也就是不想從 buffer 開頭開始寫,那麼修改一下 off 即可(假設偏移量爲5),有改動的部分如下:
fis.read(buffer, 5, buffer.length - 5);
for(int i = 0; i < buffer.length - 5; i++)
{
System.out.println(buffer[i]);
}
此時再次運行代碼,可以看到如下效果,會發現,前5個字符,變成0了,從第6個字符開始寫。
又有問題啦,我的文件中是一個字符串,這個地方爲啥是 ASCII 碼?這是由於我們的數組類型決定的,讀取出來變成 byte 類型了,想要還原爲字符,加上一個轉換即可
String s = new String(buffer);
System.out.println(s);
此時再看打印內容,就會發現恢復正常了
5 字節流的使用
問題:我們需要把 from 文件的內容,通過字節流的方式,複製到 to 文件中,應該如何去做?
解答:之前關於字節流的使用,已經學會了如何讀取文件,那同樣的,我們把讀取到的文件,使用對應的函數寫入到目的文件,不就可以了嗎?嘗試代碼如下:
import java.io.*; // 導入類
class Test
{
public static void main(String args[])
{
// 聲明輸入流引用
FileInputStream fis = null;
// 聲明輸出流的引用
FileOutputStream fos = null;
try
{
// 生成代表輸入流的對象
fis = new FileInputStream("from.txt");
// 生成代表輸出流的對象
fos = new FileOutputStream("to.txt");
// 生成一個字節數組
byte [] buffer = new byte[100];
// 調用輸入流對象的read方法,讀取數據
int temp = fis.read(buffer, 0, buffer.length);
// 讀出來多少數據,就寫進去多少數據
fos.write(buffer, 0, temp);
}
catch(Exception e)
{
System.out.println(e);
}
}
}
上述代碼的運行結果,如果我們沒有打印的話,在終端上是看不到任何變化的, 不過我們能看到目的文件 to 中,有內容了,大小也變了。
分析一下上邊的代碼,其實就多了三條語句,一條是聲明輸出流的引用;一條是生成代表輸出流的對象;還有一條是寫函數,這就完成了我們想要的操作。
溫馨提示:要好好利用 read 的返回值,是讀到了多長的數據,如果不用這個,而直接用數組的總長度,則寫到文件中的,在數據不夠這個總長度的情況下就會有很多 null。
6 總結
-
I/O系統的主要目標是爲了對數據進行讀寫操作;
-
數據的流向以Java程序爲參照物;
-
I/O流可以有三種分類方法;
-
read 方法和 write 方法;
如果文章內容有誤,麻煩評論/私信多多指教,謝謝!如果覺得文章內容還不錯,留個讚唄,您的點贊就是對我最大的鼓勵,謝謝您嘞!