概述
1、数据流
在电脑上的数据有三种存储方式:外存、内存和缓存。数据流是一组有序、有起点和终点的字节的数据序列,包括输入流和输出流。Java 数据流分为两种:字节流
(Byte)和字符流
(Character)。采用数据流的目的就是使得输出输入独立于设备。
(1)数据流分类
① 字节流
以8位为单位对二进制数据进行操作
。这些类都是InputStream和OutputStream的子类。
字节流中最小的数据单元是字节(8位)。
② 字符流
以字符为单位对数据进行操作,在读的时候,将二进制数据转换为字符,在写时,将字符转换为二进制数据
。这些类都是Reader和Writer的子类。
字符流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节(16位)。
两者区别:
①
字节流可用于任何类型的对象
,包括二进制对象,处理单元为1个字节,操作字节和字节数组;字符流只能处理字符或者字符串
,处理单元为2个字节的Unicode字符,操作字符、字符数组或字符串。
② 如果是处理音频文件、图片、歌曲等,建议使用字节流;如果处理纯文本数据,建议使用字符流。
③所有文件的储存是都是字节(byte)的储存
。字符流在写入文本数据时,先把字符编码成字节,再储存这些字节到磁盘;在读取文本文件时,先将字节序列转换成成字节序列再处理。
(2)输入流与输出流
一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。
① 输入流(Input Stream)
程序从输入流读取数据源(数据:外界——>程序)
。数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道。
Input Stream 不关心数据源来自何种设备(键盘,文件,网络)。
② 输出流(out Stream)
程序向输出流写入数据(数据:程序——>外界)
。将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。
Output Stream 不关心数据的目的是何种设备(键盘,文件,网络)。
2、Java 的 I/O 体系
在整个Java.io包中最重要的就是5个类和一个接口:5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable。
Java I/O主要包括如下几个层次,包含三个部分:
(1)
流式部分
――IO的主体部分
如:InputStream类(二进制格式操作)、OutputStream(二进制格式操作)、Reader类(文件格式操作)和Writer类(文件格式操作)。
(2)非流式部分
――主要包含一些辅助流式部分的类
如:File类(文件特征与管理)、RandomAccessFile类(随机文件操作)和FileDescriptor等类;(3)
其他类
–文件读取部分的与安全相关的类
如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。
Java 中的 I/O 操作主要是基于数据流进行操作的,输入流用于从源读取数据,输出流用于向目标写数据。
一、字符数据流(Writer/Reader)
字符流就是
在字节流的基础上,加上编码形成的数据流
。在读的时候将二进制数据转换为字符,在写时将字符转换为二进制数据。
,字符流适用于处理字符数据(诸如文本文件)
。
字符流出现的原因:因为字节流在操作字符时,可能会有中文导致的乱码,所以由字节流引申出了字符流
。
1、Reader抽象类
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
主要成员方法:
测试流是否可以读取
boolean ready() throws IOException;
读取一个字符,返回值为读取的字符
public int read() throws IOException;
读取 cbuf.length 长度的数据放到 cbuf 数组中,返回值为实际读取的字符的数量
public int read(char cbuf[]) throws IOException;
读取 len 个字符,存放到偏移量为off的 cbuf 数组中,返回值为实际读取的字符数量,该方法必须由子类实现
public abstract int read(char cbuf[],int off,int len) throws IOException;
关闭数据流
public void close() throws IOException;
(1)FileReader(外存文件读入数据)
文件字符输入流。
创建一个 FileReader 对象指向要读取的文件,用于把硬盘文件中的数据以字符的方式读取到内存中
。
构造函数:
// 1、以文件路径的字符串作为参数
FileReader f = new FileReader(“c:/temp.txt”);
// 2、将File对象作为其参数
File f = new file(“c:/temp.txt”);
FileReader f1 = new FileReader(f);
(2)InputStreamReader
从输入流读取字节,在将它们转换成字符 。
构造函数
Public inputstreamReader(inputstream is);
(3)CharArrayReader(从内存字符数组读入数据)
CharArrayReader 是一个把字符数组作为源的输入流的实现
。该类实现了一个将内存中的字符数组用作字符输入流的字符缓冲区(数据源),即该类可利用字符缓冲区当做字符输入流进行读取工作。
构造函数:
CharArrayReader(char array[ ])
CharArrayReader(char array[ ], int start, int numChars)
示例:
public class Main {
public static void main(String[] args) throws Exception {
char[] ch = {
'H', 'E', 'L', 'L', 'O' }; // 定义一个字符数组作为数据源
CharArrayReader car = new CharArrayReader(ch); // 以数据源作为参数创建字符缓冲区对象
int value = 0;
while ((value = car.read()) != -1) {
char c = (char) value;
System.out.print(c + " : ");
System.out.println(value);
}
}
}
输出结果:
(4)StringReader(从内存字符串读入)
StringReader 是一个把字符串作为源的输入流的实现
。该类实现了一个将内存中的字符串用作字符输入流的字符缓冲区(数据源),即该类可利用字符缓冲区当做字符输入流进行读取工作。
构造函数:
StringReader(String str);
(5)BufferedReader(提供缓冲功能)
BufferedReader 是缓冲字符输入流,作用是
为其他字符输入流提供缓冲功能(拥有 8192 字符的缓冲区)
,而且提供了很实用的 readLine,读取一个文本行(reader.readLine()方法返回的一行字符中不包含换行符,所以输出的时候要自己加上换行符),从字符输入流中读取文本
,缓冲各个字符,从而提供字符、数组和行的高效读取。
创建BufferReader时,我们会通过它的构造函数指定某个Reader为参数。BufferReader会将该Reader中的数据分批读取,每次读取一部分到缓冲中;操作完缓冲中的这部分数据之后,再从Reader中读取下一部分的数据。
为什么需要缓冲呢?缓冲中的数据实际上是保存在内存中,而原始数据可能是保存在硬盘或NandFlash中;而我们知道,从内存中读取数据的速度比从硬盘读取数据的速度至少快10倍以上。
源码关键字段
// 字符输入流
private Reader in;
// 字符缓冲区
private char cb[];
//读取字符存储的最末下标+1
private int nChars;
//读取字符存储的起始下标
private int nextChar;
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
// 仅在markedChar为0时有效
private int readAheadLimit = 0;
// 如果下个字符是换行符,则跳过--专用于readLine()方法里面控制
private boolean skipLF = false;
// 设置标志时的markedSkipLF--用于mark()方法的变量
private boolean markedSkipLF = false;
// 默认的字符缓冲大小
private static int defaultCharBufferSize =8192;
//用于readLine()方法时初始化StringBuffer的初始容量
private static int defaultExpectedLineLength = 80;
构造函数
public BufferedReader(Reader in); //创建缓冲区字符输入流
public BufferedReader(Reader in,int size); //创建输入流并设置缓冲区大小
示例:
FileReader fd = new FileReader("java.txt"); // 创建一个 FileReader 对象
BufferReader mbr = new BufferedReader(fd); // 以 FileReader 对象为参数,创建 BufferReader 对象
String line = null;
while((line = mbr.myReadLine())!= null) {
//读取文本行
System.out.println(line)
}
(6)PipedReader
管道字符输入流,用于
读取对应绑定的管道字符输出流写入其内置字符缓存数组buffer中的字符
,借此来实现线程之间的通信
、pr中专门有两个方法供pw调用、receive(char c)、receive(char[] b, int off, intlen)、使得pw可以将字符或者字符数组写入pr的buffer中。
构造方法
PipedReader(PipedWriter src) // 使用默认的buf的大小和传入的pw构造pr
PipedReader(PipedWriter src, int pipeSize) // 使用指定的buf的大小和传入的pw构造pr
PipedReader() // 使用默认大小构造pr
PipedReader(int pipeSize) // 使用指定大小构造pr
源码关键字段:
public class PipedReader extends Reader {
// 标记PipedWriter是否关闭
boolean closedByWriter = false;
// 标记PipedReader是否关闭
boolean closedByReader = false;
// 标记PipedWriter与标记PipedReader是否关闭的连接是否关闭
boolean connected = false;
// 拥有PipedReader的线程
Thread readSide;
// 拥有PipedWriter的线程
Thread writeSide;
//用于循环存放PipedWriter写入的字符数组的默认大小
private static final int DEFAULT_PIPE_SIZE = 1024;
//用于循环存放PipedWriter写入的字符数组
char buffer[];
// buf中下一个存放PipedWriter调用此PipedReader的receive(int c)时、c在buf中存放的位置的下标。
// in为-1时、说明buf中没有可读取字符、in=out时已经存满了。
int in = -1;
// buf中下一个被读取的字符的下标
int out = 0;
}
2、Writer 抽象类
写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
主要成员方法:
将指定字符添加到此 writer,
返回流对象本身
(也就是可以写成这种格式: append().append())public Writer append(char c) ;
将指定字符序列添加到此 writer,返回流对象本身(也就是可以写成这种格式: append().append())
public Writer append(CharSequence csq) ;
将指定字符序列的子序列添加到此 writer.Appendable,返回流对象本身(也就是可以写成这种格式: append().append())
public Writer append(CharSequence csq, int start, int end) ;
将整型值c的低16位写入输出流
public void write(int c) throws IOException;
将字符数组 cbuf[] 写入输出流 ,从而将其输出到 Writer 对象指定的位置
public void write(char cbuf[]) throws IOException;
将字符数组 cbuf[] 中的从索引为off的位置处开始的len个字符写入输出流 ,从而将其输出到 Writer 对象指定的位置
public abstract void write(char cbuf[],int off,int len) throws IOException;
将字符串str中的字符写入输出流 ,从而将其输出到 Writer 对象指定的位置
public void write(String str) throws IOException;
将字符串str 中从索引off开始处的len个字符写入输出流 ,从而将其输出到 Writer 对象指定的位置
public void write(String str,int off,int len) throws IOException;
刷空输出流,并输出所有被缓存的字节。
flush( )
关闭流 ,释放系统资源,关闭前会刷新缓冲区。
close()
(1)FileWrite(将数据写入外存文件)
FileWriter 类对象,用于将字符类型数据写入文件。构造函数
第一个参数表明创建对象时要指定输出的地址
,第二个参数表明我在输出的时候是否要覆盖源内容(默认为false覆盖)
,可以加一个参数true表示追加不覆盖。
构造函数:
FileWriter(File file) // 给一个File对象构造一个 FileWriter 对象。
FileWriter(File file, boolean append) // 给一个File对象构造一个 FileWriter 对象。
FileWriter(FileDescriptor fd) // 构造与文件描述符关联的 FileWriter 对象。
FileWriter(String fileName) // 根据一个给定文件的路径创建 FileWriter 对象。
FileWriter(String fileName, boolean append) // 根据一个给定文件的路径构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据
示例:
File file = new File("D:\\www\\love.txt"); // 定义一个File类的对象
Writer out = new FileWriter(file); // 多态的写法
out.write(97); // 97-->对应的字符a 输出a
out.write("\r\n"); // 换行
out.write('a'); // a
out.write('我'); // 我
out.write("我爱中国"); // 我爱中国
out.write("我爱中国",2,2); // 中国
//定义一个字符数组
char[] ch = {
'我','爱','世','界'};
out.write(ch); // 我爱世界
out.write(ch,2,2); // 世界
out.flush(); // 刷新输出流
out.write("可以继续输出"); //可以继续输出
out.close(); // 关闭流
out.write(97); // 会报错,因为此时的流已经关闭。java.io.IOException: Stream closed
(2)CharArrayWrite(向内存字符数组写入数据)
字符数组输出流,用于
将字符写入到内存中的字符缓存数组 char[] buf 中
,当此数组存满时会自动扩容
。
在此类上调用 close() 无效,即 close 方法对CharArrayWriter没有影响,可以在流关闭后继续调用此类的方法而不生成IOException
。
源码关键字段:
public class CharArrayWriter extends Writer {
// 字符数组缓冲
protected char buf[];
// 字符数组缓冲大小
protected int count;
}
构造函数:
CharArrayWriter caw = new CharArrayWriter(); // 创建使用默认大小的CharArrayWriter对象
CharArrayWriter caw = new CharArrayWriter(int initialSize); // 创建大小为 initialSize 的CharArrayWriter对象
示例:
char[] ArrayLetters = new char[] {
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
// 创建CharArrayWriter字符输出流
CharArrayWriter caw = new CharArrayWriter();
// 写入“A”个字符
caw.write('A');
// 写入字符串“BC”个字符
caw.write("BC");
//System.out.printf("caw=%s\n", caw);
// 将ArrayLetters数组中从“3”开始的后5个字符(defgh)写入到caw中。
caw.write(ArrayLetters, 3, 5);
//System.out.printf("caw=%s\n", caw);
// (01) 写入字符0
// (02) 然后接着写入“123456789”
// (03) 再接着写入ArrayLetters中第8-12个字符(ijkl)
caw.append('0').append("123456789").append(String.valueOf(ArrayLetters), 8, 12);
System.out.printf("caw=%s\n", caw);
输出:
(3)StringWriter
StringWriter是
将一个 StringBuffer 对象作为输出目的地
,并且可以在构造函数指定 buffer 的大小。
StringWriter只是将数据写入到一个 buffer 对象中,而不是实质的物理介质,这个对象最后又可以转换成字符串(toString)
。
在字符串缓冲区中收集输出的字符流,可用于构造字符串,关闭流无效,关闭后调用其他方法不会报异常
。
源码关键字段:
public class StringWriter extends Writer {
// StringBuffer 字符串缓冲
private StringBuffer buf;
}
构造函数:
StringWriter = new StringWriter(); // 创建使用默认大小的 StringWriter 对象
StringWriter = new StringWriter(int initialSize); // 创建大小为 initialSize 的 StringWriter 对象
示例:
StringWriter stringWriter = new StringWriter();
stringWriter.write("中国");
stringWriter.append("人民");
String str = stringWriter.toString(); // 将 stringWriter 对象最后又可以转换成字符串
System.out.println(str);
输出:
(4)BufferedWriter
BufferedWriter 是缓冲字符输出流,作用是
为其他字符输出流提供缓冲功能(拥有 8192 字符的缓冲区)
。
使用 BufferedWriter 时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出
。
关闭此流时,要先刷新它,强行将缓冲区中的数据写出。否则可能无法写出数据。
。
源码关键字段:
public class BufferedWriter extends Writer {
//字符输出流
private Writer out;
//字符缓冲区
private char cb[];
//设置的字符缓冲区大小变量
private int nChars;
//字符缓冲区中的已存储元素的位置
private int nextChar;
//默认字符缓冲区大小
private static int defaultCharBufferSize = 8192;
/**
* 行分割字符串-
* property at the moment that the stream was created.
*/
private String lineSeparator;
}
构造函数:
BufferedWriter(Writer out); // 默认缓冲区大小构造字符缓冲输出流对象
BufferedWriter(Writer out,int size); // 指定缓冲区大小
(5)PipedWriter
管道字符输出流,用于
将当前线程的指定字符写入到与此线程对应的管道字符输入流中去
、所以PipedReader(pr)、PipedWriter(pw)必须配套使用、缺一不可
。管道字符输出流的本质就是调用pr中的方法将字符或者字符数组写入到pr中、这一点是与众不同的地方。所以pw中的方法很少也很简单、主要就是负责将传入的pr与本身绑定、配对使用、然后就是调用绑定的pr的写入方法、将字符或者字符数组写入到pr的缓存字符数组中
。
源码关键字段:
public class PipedWriter extends Writer {
//与此PipedWriter绑定的PipedReader
private PipedReader sink;
//标示此流是否关闭。
private boolean closed = false;
}
构造方法
PipedReader(PipedWriter src) // 使用默认的buf的大小和传入的pw构造pr
PipedReader(PipedWriter src, int pipeSize) // 使用指定的buf的大小和传入的pw构造pr
PipedReader() // 使用默认大小构造pr
PipedReader(int pipeSize) // 使用指定大小构造pr
二、字节数据流(InputStream/OutputStream)
在Java中,字节流一般适用于
处理字节数据(诸如图片、视频)
,InputStream 和 OutputStream
分别是字节输入流与字节输出流的基类,它们的子类都是字节流,主要用在按字节来处理二进制数据。
1、InputStream 类
InputStream 为字节输入流,它本身为一个抽象类,必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类。 继承自InputStream 的流都是向程序中输入数据的,且数据单位为字节(8bit)。
主要方法
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
int available()
关闭此输入流并释放与该流关联的所有系统资源。
void close()
在此输入流中标记当前的位置。
void mark(int readlimit)
测试此输入流是否支持 mark 和 reset 方法。
boolean markSupported()
从输入流中读取数据的下一个字节。
abstract int read()
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int read(byte[] b)
将输入流中最多 len 个数据字节读入 byte 数组。
int read(byte[] b, int off, int len)
将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。
void reset()
跳过和丢弃此输入流中数据的 n 个字节。
long skip(long n)
(1)FileInputStream
从文件系统中的某个文件中获得输入字节,用于读取诸如
图像
数据之类的原始字节流。
构造函数
FileInputStream(File file) // 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(FileDescriptor fdObj) // 通过使用文件描述符 fdObj 创建一个 FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接。
FileInputStream(String name) // 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
(2)ObjectInputStream
对象输入流,
对使用 ObjectOutputStream 写入的对象进行反序列化
。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。
ObjectInputStream 用于恢复那些以前序列化的对象。用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取
。
对象要能从流中读取,它必须是可序列化的;读取的顺序应该与写入时的顺序是一致的
。
构造方法
ObjectInputStream(InputStream in); // 创建从指定 InputStream 读取的 ObjectInputStream。
示例
private static void read() throws FileNotFoundException, IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
// 顺序读取
int readInt = ois.readInt();
String string = (String) ois.readObject();
Date date=(Date) ois.readObject();
System.out.println("readInt="+readInt);
System.out.println("string="+string);
System.out.println("date="+date);
ois.close();
}
(3)ByteArrayInputStream
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可继续读取,而不会产生任何 IOException
。
构造方法
ByteArrayInputStream(byte[] buf) // 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
ByteArrayInputStream(byte[] buf, int offset, int length) // 创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
示例
private static void test1() {
byte[] buf=new byte[]{
'h','e','l','l','o'};
// 用一个字节数组来构造一个ByteArrayInputStream
ByteArrayInputStream bais=new ByteArrayInputStream(buf,0,3);
byte[] buff=new byte[bais.available()-1];
try {
bais.read(buff);
System.out.println(new String(buff));
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
bais.close(); // 关闭 ByteArrayInputStream 无效,是一个空实现
} catch (IOException e) {
e.printStackTrace();
}
}
// 仍然可以继续读
int read = bais.read();
System.out.println((char)read);
}
(4)BufferInputStream
BufferedInputStream 是 FilterInputStream 的子类,作为过滤器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。并且
支持 mark() 标记和 reset() 重置方法
,mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。
BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置
。
不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
源码关键字段
//内置缓存字节数组的大小 8KB
private static int defaultBufferSize = 8192;
//内置缓存字节数组
protected volatile byte buf[];
//当前buf中的字节总数、注意不是底层字节输入流的源中字节总数
protected int count;
//当前buf中下一个被读取的字节下标
protected int pos;
//最后一次调用mark(int readLimit)方法记录的buf中下一个被读取的字节的位置
protected int markpos = -1;
//调用mark后、在后续调用reset()方法失败之前云寻的从in中读取的最大数据量、用于限制被标记后buffer的最大值
protected int marklimit;
//返回底层流对应的源中有效可供读取的字节数
int available();
//关闭此流、释放与此流有关的所有资源
void close();
//查看此流是否支持mark
boolean markSupport();
//标记当前buf中读取下一个字节的下标
void mark(int readLimit);
//读取buf中下一个字节
int read();
//读取buf中下一个字节
int read(byte[] b, int off, int len);
//重置最后一次调用mark标记的buf中的位子
void reset();
//跳过n个字节、 不仅仅是buf中的有效字节、也包括in的源中的字节
long skip(long n);
构造函数
BufferedInputStream(InputStream in) // 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size) // 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
(5)PipedInputStream
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。 通常,
数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream
。
不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程
。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开
。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
管道连接的方法
①在构造时以管道输出流对象做参数来构造,即使用PipedInputStream(PipedOutputStream src) 构造;
②使用connect(PipedOutputStream src) 方法来建立连接;
构造函数
PipedInputStream() // 创建尚未连接的 PipedInputStream。
PipedInputStream(int pipeSize) // 创建一个尚未连接的 PipedInputStream,并对管道缓冲区使用指定的管道大小。
PipedInputStream(PipedOutputStream src) // 创建 PipedInputStream,使其连接到管道输出流 src。
PipedInputStream(PipedOutputStream src, int pipeSize) // 创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。
示例
public class PipedStream {
public static void main(String[] args) throws IOException {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
// 使输入管道流与输出管道流联通
input.connect(output);
// 将其放在两个线程里,避免发生死锁
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}
}
class Input implements Runnable {
private PipedInputStream in;
Input(PipedInputStream in) {
this.in = in;
}
public void run() {
try {
byte[] buf = new byte[1024];
int len = -1;
while ((len = in.read(buf)) != -1) {
//read 读取从管道输出流写入的数据,没有读到数据则阻塞
String s = new String(buf, 0, len);
System.out.println("s=" + s);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Output implements Runnable {
private PipedOutputStream out;
Output(PipedOutputStream out) {
this.out = out;
}
public void run() {
try {
while (true) {
// 模拟数据写入
Thread.sleep(3000);
out.write("Output管道写入的数据!".getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2、OutputStream 类
转载:https://blog.csdn.net/IT__learning/article/details/116743206