Java4Android自學記錄(22-1):java中的I/O

道阻且長,行則將至。埋頭苦幹,不鳴則已,一鳴驚人!加油,騷年!

目錄及資源索引

  Java4Android自學過程目錄及資源索引

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的分類

  按照老師的講解,大致有三種分類方法

  • 第一種分法
  1. 輸入流;
  2. 輸出流
  • 第二種分法
  1. 字節流
  2. 字符流
  • 第三種分法
  1. 節點流
  2. 處理流

  字節流:以字節爲基礎;

  字符流:是以字符爲基礎;每次讀寫,都是一個或者幾個字符;

  節點流:真正處理數據的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 ,則上述代碼運行後的結果如下:
image-20200524150143551

  由上述運行結果可以看到,把 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個字符開始寫。
image-20200524145811170

  又有問題啦,我的文件中是一個字符串,這個地方爲啥是 ASCII 碼?這是由於我們的數組類型決定的,讀取出來變成 byte 類型了,想要還原爲字符,加上一個轉換即可

String s = new String(buffer);

System.out.println(s);

  此時再看打印內容,就會發現恢復正常了
image-20200524145201365

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 總結

  1. I/O系統的主要目標是爲了對數據進行讀寫操作;

  2. 數據的流向以Java程序爲參照物;

  3. I/O流可以有三種分類方法;

  4. read 方法和 write 方法;

如果文章內容有誤,麻煩評論/私信多多指教,謝謝!如果覺得文章內容還不錯,留個讚唄,您的點贊就是對我最大的鼓勵,謝謝您嘞!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章