------- android培训、java培训、期待与您交流! ----------
Io中关闭流close()方法是为了释放掉十分有限的操作系统资源。由于输入输出要调用底层的系统资源。
调用输出流(FileWriter)的writer方法的时候,并没有将数据写入到目的地中,而是写到了内存当中(流的缓冲区中),也可以理解为其实写到了流中,下一步我们就是将这些内存中(或流中)的数据写到目的地中,调用flush方法,将清空输入流,也就是将所有缓冲的数据发送到目的地。 注意,这里使用的缓冲区是底层系统提供的缓冲区.
字符流使用底层系统提供的缓冲区的原因:字符流它其实是一样走的字节,但是需要将字节临时的存起来,比方说,我读一个字符(占两个字节),我不能从文件中直接读一个字节,因为那样只能读半个中文,也就是将多个字节存放到这个系统提供的缓冲区中,然后使用编码表去对照这个系统缓冲区中的字节数据,去取出相应的字符。这就是InputStreamWriter对象做的事情。所以需要刷新
而对于字节流来说,没有使用这个缓冲区。因为无需转换。所以不需要刷新。
而对于自己创建的缓冲区来说:
BufferedInputStream与 BufferedOutputStream
BufferedReader 和BufferedWriter 类
它们内部实现了一个数组,先将数据放到这个数组中,然后一遍写到文件中(当然,对于字符缓冲区来说,还需要经过系统提供的缓冲区去编码),在读文件的时候,调用了fill()先将文件中的数据存储到这个数组中,然后再去操作数据的时候,从数组中直接拿就可以,不用每次取数据都去文件中取。如果缓冲区去完,则再去调用fill装满缓冲区。这样就可以对这个数组进行操作了,可以方便的取出一行数据,在数组中判断标志位。
而就在字符写入到这个底层缓冲区的时候,提供了字符编码的转换。。。
对于字符流中底层缓冲区,调用flush()的时候,将底层缓冲区刷新后写入文件数据。
而Io输出流中的 flush()方法的作用:
被置于缓冲区中的数据,是为了用更大的包的形式传递的字符(节省了系统资源,不必每次输入都调用底层资源一个个的去写入)在关闭输出流时候都将被送出。
而flush()的作用就是清空输出流,也就是将所有缓冲中的数据发送到目的地。
其实无论字符流还是字节流,底层都是使用字节流的形式往相应的文件对象中写入输入,仅仅是字符流封装了字节流
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
其实就是将这个字符流转换为一个字节流,而将这个字节流转成一个转换流的形式对数据进行写出。
而在字符流输出的时候,也是使用的字节的方式输出。仅仅是提供了编码转换。
对于PrintWirter,来说,它的底层调用了write(s)
public void println(String x) {
synchronized (lock) {
print(x);
println();
}
}
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
而write的调用,如果PrintWriter在构造的时候传入了一个OutputStream,则将这个OutputStream利用OutputStreamWriter转成字符流,然后再调用其上的write方法。
public PrintWriter(OutputStream out, boolean autoFlush) {
this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
// save print stream for error propagation
if (out instanceof java.io.PrintStream) {
psOut = (PrintStream) out;
}
}
而对于普通的字符流来说,PrintWriter调用其上的writer即可。
不能使用字符流去对二进制文件进行复制:
原因:由于字符流要对二进制文件进行转码,可能对应的字节在编码表中不存在,故生成形如???的字符,再去转码的时候,就不知道该怎么去将这些码转换成为二进制数据了。
当我们使用字节流去一个个的读取数据的时候,特别要注意,当某个二进制资源的格式为11111111-1010101001010101010010101也就是这种形式时候,由于第一个字节转成int类型为-1,所以就停止读了,必须要通过方法去解决。也就是为什么read方法返回一个int类型而不是byte类型的原因。
Byte -1----->int -1 但是将一个字节变成了4个字节去存放。为了避免读到的数据-1和结束标记相同,就将这个数据(-1)的字节前边补0
也就是将读取到的数据(-1)变成了0000000000000000 00000000 1111111
从而返回的数据就不是-1了,而是其他的一个int数字,当我通过write写这个数据的时候,将这个int数据00000000 00000000 00000000 1111111传入到一个write(int a)的方法中写入,这个函数将前三个字节忽略,完成了数据的转换。