第四十八講 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);
}
}
}