1 裝飾模式
Java中IO使用的是裝飾模式,裝飾模式在Android中很常見(jiàn),比如系統(tǒng)的Context。

裝飾模式的模型

-
Component:抽象構(gòu)建接口。 -
ConcreteComponent:具體的構(gòu)建對(duì)象,實(shí)現(xiàn)組件對(duì)象接口,通常就是被裝飾的原始對(duì)象。就對(duì)這個(gè)對(duì)象添加功能。 -
Decorator:所有裝飾器的抽象父類(lèi),需要定義 一個(gè)與組件接口一致的接口,內(nèi)部持有一個(gè)Component對(duì)象,就是持有一個(gè)被裝飾的對(duì)象。 -
ConreteDecoratorA/ConreteDecoratorB:實(shí)際的裝飾器對(duì)象,實(shí)現(xiàn)具體添加功能。
2 流式部分
2.1 I/O體系

IO流需要站在內(nèi)存的角度去理解:讀入寫(xiě)出。
讀入:將文件從外部讀入內(nèi)存中。
寫(xiě)出:從內(nèi)存中生成一個(gè)文件。

2.2 字節(jié)流

BufferInputStream+FileInputStream
Buffer:緩存,作用是提升性能,原理是減少磁盤(pán)的磁頭操作次數(shù)。
只能讀寫(xiě)byte類(lèi)型的數(shù)據(jù)。
File file = new File("txt/BufferedStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read();
BufferOutputStream+FileOutputStream
File file = new File("txt/BufferedStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(byteArray[0]);
bos.write(byteArray, 1, byteArray.length - 1);
//flush()的作用是強(qiáng)制進(jìn)行一次IO,比如最后寫(xiě)出的數(shù)據(jù)不夠緩存指定的長(zhǎng)度,就需要強(qiáng)制的執(zhí)行一次IO
bos.flush();
bos.close();
完整示例:
package site.exciter.learn.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedStreamTest {
private static final byte[] byteArray = {
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
};
public static void main(String[] args) {
testBufferedInputStream();
// testBufferedOutputStream();
}
private static void testBufferedInputStream() {
try {
File file = new File("txt/BufferedStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
//讀取前10個(gè)字節(jié)并輸出在控制臺(tái)
for (int i = 0; i < 10; i++) {
if (bis.available() >= 0) {
System.out.println(byteToString((byte) bis.read()));
}
}
//在此輸入流中標(biāo)記當(dāng)前的位置,對(duì)reset方法的后續(xù)調(diào)用會(huì)在最后標(biāo)記的位置重新定位此流,以便后續(xù)重新讀取相同的字節(jié)。
bis.mark(2000);
//跳過(guò)并從輸入流中丟棄10字節(jié)的數(shù)據(jù)。
bis.skip(10);
//跳10個(gè)字節(jié)之后讀取剩余的部分
byte[] b = new byte[1024];
int n1 = bis.read(b, 0, b.length);
System.out.println("n1的值為:" + n1);
printByteValue(b);
//調(diào)用reset之后,再次讀取會(huì)從mark標(biāo)記的位置開(kāi)始,也就是從第10個(gè)字節(jié)開(kāi)始讀取。
bis.reset();
int n2 = bis.read(b, 0, b.length);
System.out.println("n2的值為:" + n2);
printByteValue(b);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void testBufferedOutputStream() {
try {
File file = new File("txt/BufferedStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(byteArray[0]);
bos.write(byteArray, 1, byteArray.length - 1);
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String byteToString(byte b) {
byte[] bArray = ;
return new String(bArray);
}
private static void printByteValue(byte[] buf) {
for (byte b : buf) {
if (b != 0) {
System.out.println(byteToString(b) + " ");
}
}
}
}
DataInputStream+BufferedInputStream+FileInputStream
可以讀寫(xiě)所有基本類(lèi)型的數(shù)據(jù)。
File file = new File("txt/DataStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
DataOutputStream+BufferedOutputStream+FileOutputStream
File file = new File("txt/DataStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
完整示例:
package site.exciter.learn.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamTest {
public static void main(String[] args) {
// testDataInputStream();
testDataOutputStream();
}
private static void testDataInputStream() {
try {
File file = new File("txt/DataStreamTest.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
System.out.println(Long.toHexString(dis.readLong()));
System.out.println(dis.readBoolean());
System.out.println(byteToString(dis.readByte()));
System.out.println(charToString(dis.readChar()));
System.out.println(shortToString(dis.readShort()));
System.out.println(Integer.toHexString(dis.readInt()));
System.out.println(Long.toHexString(dis.readLong()));
System.out.println(dis.readUTF());
System.out.println(Long.toHexString(dis.readLong()));
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void testDataOutputStream() {
try {
File file = new File("txt/DataStreamTest.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeBoolean(true);
dos.writeByte((byte) 0x41);
dos.writeChar((char) 0x4243);
dos.writeShort((short) 0x4445);
dos.writeInt(0x12345678);
dos.writeLong(0x987654321L);
dos.writeUTF("abcdefg");
dos.writeLong(0x23433L);
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String byteToString(byte val) {
return Integer.toHexString(val & 0xff);
}
private static String charToString(char val) {
return Integer.toHexString(val);
}
private static String shortToString(short val) {
return Integer.toHexString(val & 0xffff);
}
}
ObjectInputStream+BufferedInputStream+FileInputStream
可以讀寫(xiě)對(duì)象,包含Object、Array、List等。
FileInputStream fis = new FileInputStream(newFile("txt/Object.txt"));
BufferedInputStream bis = new BufferedInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(bis);
while (ois.available() != -1) {
Object object = ois.readObject();
Book book = (Book) object;
System.out.println(book.toString());
}
ois.close();
ObjectOutputStream+BufferedOutputStream+FileOutputStream
FileOutputStream fos = new FileOutputStream("txt/Object.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
for (int i = 0; i < 10; i++) {
oos.writeObject(new Book("三國(guó)演義", 102.0f));
}
oos.close();
2.3 字符流

BufferedReader+InputStreamReader+FileInputStream
FileInputStream fis = new FileInputStream("txt/InputStreamWriterTest.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String str;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
BufferedWriter+OutputStreamWriter+FileOutputStream
File file = new File("txt/OutputStreamWriterTest.txt");
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
bw.write("new bee");
bw.flush();
bw.close();
使用上述方式就可以讀寫(xiě)文件,但是過(guò)程過(guò)于繁瑣,可以使用FileReader/FileWriter來(lái)簡(jiǎn)化流程。
BufferedReader+FileReader/BufferedWriter+FileWriter
File srcFile = new File("txt/BufferedReaderTest.txt");
File dstFile = new File("txt/BufferedWriterTest.txt");
FileReader fr = new FileReader(srcFile);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(dstFile);
BufferedWriter bw = new BufferedWriter(fw);
char[] str = new char[1024];
while ((br.read(str)) != -1) {
bw.write(str);
}
br.close();
bw.flush();
bw.close();
2.4 InputStream-Reader

2.5 OutputStream-Writer

3 非流式部分
3.1 RandomAccessFile
特點(diǎn)
1、既可以讀也可以寫(xiě)。
RandomAccessFile不屬于InputStream和OutputStream類(lèi)系的它是一個(gè)完全獨(dú)立的類(lèi),所有方法(絕大多數(shù)都只屬于它自己)都是自己從頭開(kāi)始規(guī)定的,這里面包含讀寫(xiě)兩種操作。
2、可以指定位置讀寫(xiě)。
RandomAccessFile能在文件里面前后移動(dòng),在文件里移動(dòng)用的seek(),所以它的行為與其它的I/O類(lèi) 有些根本性的不同。總而言之,它是一個(gè)直接繼承Object的,獨(dú)立的類(lèi)。只有RandomAccessFile才有seek方法,而這個(gè)方法也只適用于文件。
功能
可以用于多線(xiàn)程分段下載,斷點(diǎn)續(xù)傳。
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.seek(10);
raf.setLength(1000);
raf.writeBoolean(true);
raf.writeChar('a');
RandomAccessFile(File file, String mode)
參數(shù) mode 的值可選 "r":可讀,"w" :可寫(xiě),"rw":可讀性。
seek(int index):可以將指針移動(dòng)到某個(gè)位置開(kāi)始讀寫(xiě)。
setLength(long len):給寫(xiě)入文件預(yù)留空間。
3.2 NIO-FileChannel
Channel是對(duì)I/O操作的封裝。
FileChannel配合著ByteBuffer,將讀寫(xiě)的數(shù)據(jù)緩存到內(nèi)存中,然后以批量/緩 存的方式read/write,省去了非批量操作時(shí)的重復(fù)中間操作,操縱大文件時(shí)可 以顯著提高效率。
package site.exciter.learn.io;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.time.Duration;
import java.time.Instant;
public class FileChannelTest {
@RequiresApi(api = Build.VERSION_CODES.O)
public static void main(String[] args) {
File sourceFile = new File("/Users/exciter/Desktop/test-01.zip");
File targetFile = new File("/Users/exciter/Desktop/test-02.zip");
targetFile.deleteOnExit();
try {
targetFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
copyFileByFileChannel(sourceFile, targetFile);
}
@RequiresApi(api = Build.VERSION_CODES.O)
private static void copyFileByFileChannel(File sourceFile, File targetFile) {
Instant begin = Instant.now();
RandomAccessFile sourceRaf = null;
RandomAccessFile targetRaf = null;
try {
sourceRaf = new RandomAccessFile(sourceFile, "r");
targetRaf = new RandomAccessFile(targetFile, "rw");
} catch (Exception e) {
e.printStackTrace();
}
FileChannel sourceFileChannel = sourceRaf.getChannel();
FileChannel targetFileChannel = targetRaf.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);
try {
while (sourceFileChannel.read(byteBuffer) != -1) {
byteBuffer.flip();
targetFileChannel.write(byteBuffer);
byteBuffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
sourceFileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
targetFileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("time:" + Duration.between(begin, Instant.now()).toMillis());
}
}
關(guān)注木水小站 (zhangmushui.cn)和微信公眾號(hào)【木水Code】,及時(shí)獲取更多最新技術(shù)干貨。