1. 程式人生 > >第四十八講 I/O流——常用IO流(資料流和記憶體操作流)

第四十八講 I/O流——常用IO流(資料流和記憶體操作流)

資料流

資料流是操作基本資料型別的流,分為資料輸入流和資料輸出流。下面分別來對它們進行介紹。

資料輸入流

概述

資料輸入流DataInputStream允許應用程式以與機器無關方式從底層輸入流中讀取基本Java資料型別。應用程式可以使用資料輸出流寫入稍後由資料輸入流讀取的資料。

資料輸出流

概述

資料輸出流DataOutputStream允許應用程式以適當方式將基本Java資料型別寫入輸出流中。然後,應用程式可以使用資料輸入流將資料讀入。

案例

寫入一些基本資料值,儲存到檔案,並讀取出來。

package cn.liayun.otherio.
datastream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class DataStreamDemo { public static void main(String[] args) throws IOException { // writeData(); readData(); } public
static void readData() throws IOException { FileInputStream fis = new FileInputStream("tempfile\\data.txt"); DataInputStream dis = new DataInputStream(fis); boolean b = dis.readBoolean(); System.out.println(b); dis.close(); } public static void writeData() throws IOException { //寫入一些基本資料值,儲存到檔案。
FileOutputStream fos = new FileOutputStream("tempfile\\data.txt"); DataOutputStream dos = new DataOutputStream(fos); dos.writeBoolean(true); dos.close(); } }

記憶體操作流

記憶體操作流是用於操作位元組陣列,處理臨時儲存資訊的,程式結束,資料就從記憶體中消失。它分為位元組陣列輸入流ByteArrayInputStream和位元組陣列輸出流ByteArrayOutputStream。該流在後續的學習中,相信你估計會碰到!下面分別來對它們進行介紹。

ByteArrayInputStream

概述

ByteArrayInputStream包含一個內部緩衝區,該緩衝區包含從流中讀取的位元組。內部計數器跟蹤read方法要提供的下一個位元組。關閉ByteArrayInputStream無效。此類中的方法在關閉此流後仍可被呼叫,而不會產生任何IOException。

ByteArrayOutputStream

概述

此類實現了一個輸出流,其中的資料被寫入一個byte陣列。緩衝區會隨著資料的不斷寫入而自動增長。可使用toByteArray()和toString()獲取資料。關閉ByteArrayOutputStream無效。此類中的方法在關閉此流後仍可被呼叫,而不會產生任何IOException。

案例

用IO流的讀寫思想運算元組。

package cn.liayun.otherio.bytearraystream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class ByteArrayStreamDemo {

	public static void main(String[] args) {
		//用IO的讀寫思想運算元組
		//1,確定源
		ByteArrayInputStream bis = new ByteArrayInputStream("abcde".getBytes());//該資料來源可以來自於檔案
		//2,確定目的,內建了一個byte陣列
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		int by = 0;
		while ((by = bis.read()) != -1) {
			bos.write(by);
		}
		
		System.out.println(bos.toString());
	}

}

涉及到IO流的兩個練習

檔案切割器

對一個檔案進行切割(一個源對應多個目的),切成碎片,而且生產的碎片檔案都有有序的編號。

package cn.liayun.otherio.splitfile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SplitFileTest {

	public static void main(String[] args) throws IOException {
		/*
		 * 檔案切割器。
		 * 一個讀取流,對應多個輸出流,而且生產的碎片檔案都有有序的編號。
		 */
		File srcFile = new File("c:\\1.mp4");
		File destDir = new File("tempfile\\partfiles");
		fileSplit(srcFile, destDir);
	}

	public static void fileSplit(File srcFile, File destDir) throws IOException {
		if (!srcFile.exists()) {
			throw new RuntimeException(srcFile.getAbsolutePath() +  "原始檔不存在");
		}
		
		if (!destDir.exists()) {
			destDir.mkdirs();
		}
		
		//1,讀取原始檔
		FileInputStream fis = new FileInputStream(srcFile);
		//2,建立目的引用
		FileOutputStream fos = null;
		//3,建立一個緩衝區(5M)
		byte[] buf = new byte[1024 * 1024 * 5];//5M
		int count = 0;
		int len = 0;
		//4,往緩衝區中儲存資料
		while ((len = fis.read(buf)) != -1) {
			//5,建立輸出流,並明確要寫入的檔案物件
			File partFiles = new File(destDir, (++count) + ".part");
			fos = new FileOutputStream(partFiles);
			fos.write(buf, 0, len);
			fos.close();
		}
		
		//應該在產生碎片檔案時,需要產生一個配置檔案。至少要記錄碎片的個數和原始檔的名字
		//partcount = 5, filename = 1.mp4
		//配置檔案中儲存的是鍵值資訊,可使用Properties集合
		Properties prop = new Properties();
		prop.setProperty("partcount", Integer.toString(count));
		prop.setProperty("filename", srcFile.getName());
		
		File configFile = new File(destDir, ++count + ".properties");
		fos = new FileOutputStream(configFile);
		prop.store(fos, "save part file info");
		
		fis.close();
		fos.close();
	}
	

}

按照位元組數擷取一個字串

按照位元組數擷取一個字串,例如"abc你好",如果擷取到半個中文,捨棄。比如擷取4個位元組,就是“abc”,擷取5個位元組,就是“abc你”。

package cn.liayun.otherio.splitfile;

public class Test {

	public static void main(String[] args) {
		/*
		按照位元組數擷取一個字串,"abc你好",如果擷取到半個中文,捨棄。比如擷取4個位元組,abc。擷取5個位元組,abc你。
		定義功能實現。
		
		字串--->位元組陣列,編碼。
		位元組陣列--->字串,解碼。
		
		友情提示:GB2312編碼的一箇中文是兩個位元組,而且兩個位元組的最高位都是1,也就是說是一個負數。
		
		思路:
		1,提示中告訴我中文兩個位元組都是負數;
		2,判斷擷取的最後一個位元組是否是負數?
		      如果不是,直接擷取。
		      如果是,就往回判斷前一個是否是負數,並記錄住負數的個數,如果連續的負數有奇數個,捨棄最後一個位元組。
		      如果連續的負數是偶數個,不捨棄,哦耶!
		*/
		
		//字串轉成位元組陣列
		String str = "abc你好";
		str = "abc琲琲cde琲琲";//-84 105
		byte[] buf = str.getBytes();
//		for (byte b : buf) {
//			System.out.print(b + ", ");
//		}
		
		for (int x = 0; x < buf.length; x++) {
			String temp = cutStringByCount(str, x + 1);
			System.out.println("擷取" + (x + 1) + "個位元組是:" + temp);
		}
	}

	public static String cutStringByCount(String str, int len) {
		//1,將字串先轉成位元組陣列,因為要判斷擷取的位元組是否是負數(先有位元組)
		byte[] buf = str.getBytes();
		//2,定義計數器,記錄住負數的個數
		int count = 0;
		//3,對位元組陣列進行遍歷,而且應該從擷取長度的最後一個位元組開始判斷,並往回判斷
		for (int x = len - 1; x >= 0; x--) {
			//4,在遍歷過程中,只要滿足了負數,就進行計數。只要不是負數直接結束遍歷
			if (buf[x] < 0) {
				count++;
			} else {
				break;
			}
		}
		
		//5,對遍歷後的計數器的值進行判斷,奇數,就捨棄最後一個位元組,並將位元組陣列轉成字串;偶數,不捨棄,將位元組陣列轉成字串
		if (count % 2 ==0) {
			return new String(buf, 0, len);
		} else {
			return new String(buf, 0, len - 1);
		}
		
	}

}