本篇將對JAVA I/O流中的字節流InputStream/OutputStream做個簡單的概括:
總得來說,每個字節流類都有一個對應的用途,如下:
再看下字節流InputStream/OutputStream的組成結構,如下圖;

接下來逐個介紹;
簡單地說,就是字節數組與字節輸入輸出流之間的各種轉換,舉個例子如下:
package io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class IOTest {
public static void main(String[] args) throws IOException {
//內存中的字節數組
byte[] bArr = new byte[]{1,2,3};
//字節輸入流
InputStream is = new ByteArrayInputStream(bArr);
//字節輸出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bff = new byte[3];
//從輸入流中讀取字節
is.read(bff,0,3);
System.out.println(bff[0] + "," + bff[1] + "," + bff[2]);
//往字節輸出流中寫入字節數組
bos.write(bff);
//從輸出流中獲取字節數組
byte[] bArryFromOs = bos.toByteArray();
System.out.println(bArryFromOs[0] + "," + bArryFromOs[1] + "," + bArryFromOs[2]);
is.close();
bos.close();
}
}
可以用FileInputStream/FileOutputStream對文件進行寫入及讀取,如下代碼,可以實現文件的復制:
package io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class IOTest {
public static void main(String[] args) throws IOException {
// 字節輸入流
InputStream is = new FileInputStream("C:\\test.jpg");
// 字節輸出流
OutputStream os = new FileOutputStream("C:\\copy_test.jpg", false);
int bTmp = -1;
while ((bTmp = is.read()) != -1) {
os.write(bTmp);
}
is.close();
os.close();
}
}
可用於同一個JVM中的兩個線程間通信,字節流傳輸,舉個例子:
package io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class IOTest {
public static void main(String[] args) throws IOException {
final PipedOutputStream pos = new PipedOutputStream();
final PipedInputStream pis = new PipedInputStream(pos);
ExecutorService es = Executors.newFixedThreadPool(2);
es.execute(new Runnable() {
@Override
public void run() {
try {
byte[] bArr = new byte[]{1,2,3};
pos.write(bArr);
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
es.execute(new Runnable() {
@Override
public void run() {
byte[] bArr = new byte[3];
try {
// 會導致線程阻塞
pis.read(bArr, 0, 3);
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(bArr[0] + "," + bArr[1] + "," + bArr[2]);
}
});
}
}
帶緩沖區的字節流,裝飾器模式在jdk中的一個應用,可用於裝飾其它字節流;
一次讀取/寫入一大塊字節到緩沖區,避免每次頻繁訪問外部媒介,提高性能;
下面是一個例子:
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOTest {
public static void main(String[] args) throws IOException {
// 字節輸入流
BufferedInputStream is = new BufferedInputStream(new FileInputStream("C:\\test.jpg"), 10 * 1024);
// 字節輸出流
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("C:\\copy_test.jpg", false));
int bTmp = -1;
while ((bTmp = is.read()) != -1) {
os.write(bTmp);
}
is.close();
os.close();
}
}
可裝飾其它字節流,實現自定義過濾字節流的基類,基本上是簡單的覆蓋了InputStream/OutputStream中的方法,意義不是很大;
可裝飾其它字節輸入流,增加的功能是是回退讀取,如下例子:
package io;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
public class IOTest {
public static void main(String[] args) throws IOException {
byte[] bArr = new byte[] { 1, 2, 3 };
// 字節輸入流
PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(bArr));
System.out.println(pis.read());
System.out.println(pis.read());
// 回退
pis.unread(1);
System.out.println(pis.read());
pis.close();
}
}
可裝飾其它字節輸入流,增加從輸入流中讀取Java基本類型數據的功能;
舉個例子:
package io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOTest {
public static void main(String[] args) throws IOException {
// 字節輸入流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("C:\\data.data"));
DataInputStream dis = new DataInputStream(new FileInputStream("C:\\data.data"));
dos.writeDouble(2.0235);
dos.writeInt(520);
dos.flush();
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
dos.close();
dis.close();
}
}
PrintStream可以裝飾其它字節輸出流,允許將格式化數據寫入到字節輸出流中,如下示例,將格式化數據寫到控制台上;
package io;
import java.io.IOException;
import java.io.PrintStream;
public class IOTest {
public static void main(String[] args) throws IOException {
// 字節輸出流
PrintStream ps = System.out;
//輸出格式化數據
ps.println("hello");
ps.printf("%5d\n", 101);
ps.write('2');
ps.close();
}
}
可以裝飾其它字節輸出流,主要用於對象序列化,可以將一個對象以字節流的形式寫入/讀取到本地文件中,如下例子:
package io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Dog implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3581113588185842098L;
private int age;
public Dog(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
}
public class IOTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("C:\\object.data"));
ObjectInputStream input = new ObjectInputStream(new FileInputStream("C:\\object.data"));
Dog dog = new Dog(2);
output.writeObject(dog);
output.flush();
Dog obj = (Dog) input.readObject();
System.out.println(obj.getAge());
output.close();
input.close();
}
}
把一個或者多個InputStream串行連接起來,第一個流讀完,繼續讀取第二個流,如下例子
package io;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
public class IOTest {
public static void main(String[] args) throws IOException {
// 內存中的字節數組
byte[] bArr = new byte[] { 1, 2, 3 };
byte[] bArr2 = new byte[] { 4, 5, 6 };
// 字節輸入流
InputStream is = new ByteArrayInputStream(bArr);
// 字節輸入流
InputStream is2 = new ByteArrayInputStream(bArr2);
// 字節輸入流,連接以上兩個流
SequenceInputStream sis = new SequenceInputStream(is, is2);
byte[] bff = new byte[3];
// 從輸入流中讀取字節
sis.read(bff, 0, 3);
System.out.println(bff[0] + "," + bff[1] + "," + bff[2]);
// 會從第二個字節流讀取數據
sis.read(bff, 0, 3);
System.out.println(bff[0] + "," + bff[1] + "," + bff[2]);
is.close();
is2.close();
sis.close();
}
}