字节流-InputStream 和 OutputStream
上篇文章我们讲了字符流的基本操作,并且通过阅读源码我们知道,字符流就是基于字节流做的实现——一次读取两个字节组成一个字符。
InputStream
此抽象类是表示字节输入流的所有类的超类。
需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。
方法名 | 方法描述 |
---|---|
available() | 返回此出入流下一个方法调用可以不受阻塞地从此输入流读取估计字节数 |
close() | 关闭此输入流并释放与该流相关联的所有系统资源 |
mark(int readlimit) | 在此输入流中标记当前的位置 |
markSupported() | 此时此输入流是否支持 mark 和 reset 方法 |
read() | 从输入流中读取数据的下一个字节 |
read(byte[] b) | 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b 中。 |
reset() | 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置 |
skip(long n) | 跳过和丢弃此输入流数据的 n 个字节 |
OutputStream
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。
方法名 | 方法描述 |
---|---|
close() | 关闭此出入流并释放与此流有关的所有系统资源 |
flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
write(byte[] b) | 将 b.length 个字节从指定的 byte 数组写入此输出流 |
write(int b) | 将指定字节写入此输出流 |
FileInputStream 和 FileOutputStream
还是以之前那个文件读写的 demo 为例,我们先看一下字节流怎么玩的~
try { // 创建读取流和写入流 FileInputStream fis = new FileInputStream("raw.txt"); FileOutputStream fos = new FileOutputStream("target.txt"); // 读取单个字符,自动往下读 byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len); } fis.close(); fos.close(); } catch (IOException e) { e.printStackTrace();}复制代码
使用 I/O 复制图片
这个操作和上面的代码一样,注意图片是二进制数据,只能使用字节流读取,不能使用字符流哦。
字节流缓冲区
这个和字符流缓冲区基本没差了,直接贴代码吧~
try { // 创建读取流和写入流 FileInputStream fis = new FileInputStream("raw.txt"); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream("target.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); // 读取单个字符,自动往下读 byte[] buf = new byte[1024]; int len; while ((len = bis.read(buf)) != -1) { bos.write(buf, 0, len); } bis.close(); bos.close(); } catch (IOException e) { e.printStackTrace();}复制代码
字节流拷贝video 等大文件
- 除文本文件之外必须使用字节流
- 文件比较大的必须使用缓冲区提升效率
代码就补贴了,同上。
自定义字节流缓冲区
这个和自定义字符流缓冲区一样,实现思想就不再赘述了,不记得的同学请翻上一篇笔记。
直接贴代码吧,没什么特别的。
class MyBufferedImputStream { private InputStream in; private byte[] buf = new byte[1024 * 8]; private int pos = 0; private int count = 0; public MyBufferedImputStream(InputStream in) { this.in = in; } // 从缓冲区一次读一个字节 public int read() throws IOException { // 通过in对象读取硬盘上的数据,存储在buf if (count == 0) { count = in.read(buf); if (count < 0) return -1; byte b = buf[pos]; count--; pos++; return b; } else if (count > 0) { byte b = buf[pos]; pos++; count--; return b; } return -1; } //关闭流 public void myClose() throws IOException { in.close(); }}复制代码
读取键盘录入
这个好像超纲了,Android 并不需要读取键盘录入。至于 EditText 是怎么读取键盘录入的,我们以后学习 EditText 源码的时候再慢慢研究。
Java 里面读取键盘录入主要用的是InputStream in = System.in;
,有需要的小伙伴自行研究吧。
转换流 InputStreamReader 和 OutputStreamWriter
java中需要转换流就会使用到转换流,使用到了 InputStreamReader/OutputStreamWriter。
我们前面也说了 FileReader 继承自InputStreamReader,内部构造方法 new FileInputStream(),因此,我们知道字符流就是字节流使用了转换流。
还是写一下代码吧,顺便讲一下上面提到的键盘录入
//获取键盘录入对象InputStream in = System.in;//转换InputStreamReader isr = new InputStreamReader(in);//提高效率BufferedReader bur = new BufferedReader(isr);String line;try { while ((line = bur.readLine()) != null) { if (line.equals("over")) break; System.out.println(line); }} catch (IOException e) { e.printStackTrace();}复制代码
没什么意思,写入转换流也是一样的操作,我就不写了。
流操作的规律
- 读取大文件记得用字*流缓冲区提高效率
- 读取文本文件优先使用字符流、其余一概用字节流
- 文件读写操作一般都是使用 FileInput(Output)Stream。