流的概念和作用
流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinking in Java>
流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
作用:为数据源和目的地建立一个输送通道
Java流分类
按流的方向分为:
- 输入流
- InputStream
- Reader
- 输出流
- OutputStream
- Writer
按处理单位分:
- 字节流
- InputStream
- OutputStream
- 字符流
- Reader
- Writer
Java中的流实现
流的使用
JDK7之前的写法
private void readFileByInputStream(File file) {
ByteArrayOutputStream outputStream = null;
InputStream inputStream = null;
try {
// 打开一个输入流
inputStream = new FileInputStream(file);
// 打开一个输出流
outputStream = new ByteArrayOutputStream();
// 构建一个缓冲的字节数组, 使用字节流的话, 一定要使用缓冲数组
// 一个字节一个字节的读取, 性能太低了
byte[] bytes = new byte[8192];
int len;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
// 这句是为了将内存中的数据刷写到磁盘中,如果不执行,不能保证磁盘中数据的完整性,这里可以忽略
outputStream.flush();
final byte[] byteArray = outputStream.toByteArray();
System.out.println(new String(byteArray));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
// 关闭流一定要try catch, 避免这个出错影响后续的流程
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
JDK7新特性 try-with-resources
private void readFileByStreamResource(File file) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream = new FileInputStream(file)) {
byte[] bytes = new byte[8192];
int len;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
outputStream.flush();
final byte[] byteArray = outputStream.toByteArray();
System.out.println(new String(byteArray));
} catch (IOException e) {
e.printStackTrace();
}
}
流使用中的注意点
1. 注意关闭打开的流
如果一直不关闭流,就无法让JVM回收对应资源,积攒多了可能出现OOM
如果实在finally里手动关闭多个流,每个close操作必须使用try catch包裹
2. 操作字节流的时候,必须使用缓存
字节流读取的时候,一次读取一个字节,但是使用byte数组的时候,可以一次读取一块内存,减少了交互次数,可以明显的提高性能
3. InputStream到底能读取几次?
正常来说,InputStream只能读取一次
不过InputStream提供了mark,markSupport,reset,通过重写这三个方法我们还是可以实现重复读取输入流的,不过需要注意大部分的流并未对这三个方式进行重写!!!
4. flush的必要性
使用outputStream时,写入的数据不会实时的写入到磁盘中,会先写到内存中,调用flush可以强制将内存中的数据写入到磁盘,防止数据丢失,close方法也会执行flush操作
5. 字节流转字符流
通过InputStreamReader和OutputStreamWriter来将字节流转为字符流
6. 字符流使用的时候,尽量使用带缓存的BufferedReader和BufferedWriter
附
- 数据保存问题
之前有小伙伴需要调用其他的接口获取用户头像,然后将获取到的头像保存为图片文件,接口返回的是byte数组,小伙伴的做法是拿到byte数组后使用ImageIO对其转换一次后再写入磁盘,导致部分头像无法显示
任何数据(文件,对象)在磁盘和内存中都是以二进制数据存在的,二进制可以转为byte数组,也就是说,任何数据都可以用byte数组表示与传递,对于这种byte数组,直接转为流持久化即可,不再需要做额外的操作 - 文件操作常见工具类
流操作多用于操作文件和Http请求,而对于文件操作,可以尽量使用Guava的Files和Java自带的Files,Java自带的Files基于nio,性能优于IO流
网友评论