0.1输入/输出流:可以从中读入/写入字节序列的对象
(想象你是一个水坝,河水流经你,你全部解析接收。把河水换成数据,河水的源头换成文件或网络,就可以直观地想象输入/输出流了)
0.2为什么要强调字节呢?字节是8位ASCII码,无法表示汉字。因此每个面向字节的操作都有对应的面向字符(两个字节的Unicode)形式的操作
0.3 I/O操作的基础是两个抽象类InputStream和OutputStream
0.4 只有三种IO:
标准IO:键盘->屏幕
文件IO:内存<->磁盘文件
串IO:某个内容<->内存指定位置
一、读写字节
- InputStream和OutputStream各有一个抽象方法用于读/写字节,虽然不常用,但是是最基础,最简单的操作。
input为abstract int read();
,这个函数读取输入流的字节,并返回读入的字节,输入流读完了再读就返回-1。由于是抽象方法,子类必须覆写。
output为abstract void write(int b);
*注意到返回类型/参数是int,因此实际程序不太喜欢用这两个函数 - 具体解析InputStream和OutputStream
//InputStream
abstract int read()//解释过了
int read(byte[] b)//把数据读入一个字节数组b,返回实际读入的字节数,最多b.length个字节
//如果开始就把输入流读完了,第二次就和普通read一样,返回-1
int read(byte[] b,int off, int length)//读入字节数组,off是从b中哪地方开始读,len是最多读入字节数
//这个read就是用来定量读入字节的
long skip(long n)//跳过n个字节不读,返回实际跳过的字节数(可能跳到输入流尾部,这样就不是n了)
int available()//返回在不阻塞情况下能读多少个字节
void close()//关闭输入流,释放系统资源。每个IO流最后都要关掉
boolean markSupported()//这个流支持打标记吗
void mark(int readlimit)//如果从输入流读的字节数少于readlimit,就在当前位置打上一个标记
void reset()//返回上一个标记
//OutputStream
abstract void write(int n)//写入一个字节
void write(byte[] b)
void write(byte[] b,int off,int len)//这两的功能和上面对应一下就知道了
void close()//关闭输出流。每个IO流最后都要关掉
void flush()//把缓冲,堵在这的数据冲出去,flush到目的地,之后缓冲区没数据了
二、扩展
单一个 InputStream和OutputStream不够用啊,我不可能永远读纯字节,我还想读文件,我还想读zip,那怎么办呢?
Java给每种可能读入和不同情况及需要的都配了类
- InputStream有常见子类如下
FileInputStream//文件读入,它的方法需提供文件路径及文件名
System.in//控制台读取
StringBufferInputStream//内存中的字符串
ByteArrayInputStream//内存中的字节数组
OutputStream有常见子类如下
FileOutputStream
System.out
ByteArrayOutputStream
- 功能不够怎么办?用FilterInputStream子类加工InputStream,out同理。步骤:
① 创建两个分别继承了FilterInputStream和 FilterOutputStream的子类
②重写read()和write()方法来实现自己想要的功能。
③ 可以定义或者重写其它方法来提供附加功能。
④这两个类由于在功能上是对称的,它们要一起被使用。
FilterInputStream常用子类
BufferedInputStream
DataInputStream
(注释写不下,写下面吧)
①BufferedInputStream:Buffer,缓冲之意。BufferedInputStream,就是缓冲字节流。好处在有缓冲,不堵塞,能加快速度。然而不能直接读取流,要套一层xxxxInputStream。
BufferedInputStream fileIn=new BufferedInputStream(new FileRaeder("xxx");
还有一个常用方法readline()一次读一行(有缓冲才敢这么干。读没缓冲的就是看到一个读一个),很方便
②DataInputStream:读入各种类型(int,double…)的数值,同样需要套一层
//读入文件内容
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("Data.txt")));
FilterOutputStream常用子类
BufferedOutputStream
//避免每次想要写入数据时都得执行实际的写入动作。它所代表的意义正是“使用缓冲区”。可以调用flush()来清出缓冲区内容。
DataOutputStream
PrintStream
只说明第三个,就是System.out.print…。
out是类 System的PrintStream类型的静态变量, 即public static final PrintStream out;
因此,System.out.println(“xxx”)是调用Stream类中的静态变量out(PrintStream类型)的println()方法。
public static final PrintStream out
不过它也有文件print。同样要隔一层
System.out.println("It's too difficult");
PrintStream fileAppend=new PrintStream(new FileOutputStream("xxx",true);
三、字符怎么办
字符,2字节。与字节的IO一一对应
普通对应关系:
FileInputStream与FileReader
FileOutputStream与FileWriter
StringBufferInputStream与StringReader
(这个没有对应)与StringWriter,因为这个可以输出Unicode而字节流没办法
ByteArrayInputStream与CharArrayReader
ByteArrayOutputStream与CharArrayWriter
过滤流的对应关系:
①BufferedInputStream与BufferedReader
②BufferedOutputStream与BufferedWriter
③DataInputStream没有对应,字符直接用就是了
④DataOutputStream同上
⑤PrintStream与PrintWriter
//举些例子
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String input = stdIn.readLine();
BufferedReader fileIn = new BufferedReader(new FileReader(“filename”));
四、过滤流发挥作用的原因:装饰模式
InputStream有子类FilterInputStream,Filter有关联关系InputStream。因此,FilterInputStream可以拥有任意一个InputStream类(想想InputStream有多少子类吧),FilterInputSream也因此可以增加无数功能,而不用给InputStream增加无数子类
就是说,当为满足各种必要的功能组合,造成单纯的继承动作产生大量subclass时,往往使用Decorator设计模式。