1、说明

InputStream和OutputStream是Java标准库中最基本的IO流,它们都位于java.io包中,该包提供了所有同步IO的功能。

2、模块:java.io.InputStream 、 java.io.OutputStream

3、用法

3.1、read&write

二者都不是接口,而是抽象类,它们分别是所有输入流和输出流的超类。这两个抽象类定义了两个最重要的方法:

  • int read():读取输入流的下一个byte,返回该byte表示的int值(0~255)。读到末尾,返回-1表示不能继续读了。
  • void write( int b ):写一个byte到输出流。虽然传入的是int,但只会写入1 byte,即该int的最低8位表示字节的部分( b & 0xff )
  1. public abstract int read() throws IOException;
  2. public abstract void write(int b) throws IOException;

3.2、实现类

FileInputStream:从文件流中读取数据

下面的代码演示了如何完整地读取一个FileInputStream的所有字节:

  1. public void readFile throws IOException{
  2. //创建一个FileInputStream对象
  3. InputStream input = new FileInputStream("src/readme.txt");
  4. for(;;){
  5. int n = input.read(); //反复调用read(),直到返回-1
  6. if(n==-1){
  7. break;
  8. }
  9. System.out.println(n);//打印byte值
  10. }
  11. input.close();
  12. }

在计算机中,应用程序如果打开了有一个文件进行读写,完成后要及时关闭,以便OS把资源释放。

FileOutputStream:将若干字节写入文件流

下面代码演示了如何将多个bytes写入文件流:

  1. public void writeFile() throws IOException{
  2. OutputStream output = new FileOutputStream("out/readme.txt");
  3. output.write(72);//H
  4. ...
  5. output.write(111);//o
  6. output.close();
  7. }

每次写入1byte太麻烦,更常见的是一次性写入多个bytes。可以通过OutputStream提供的重载方法void write( byte[ ] )来实现:

  1. public void writeFile() throws IOException{
  2. OutputStream output = new FileOutputStream("out/readme.txt");
  3. output.write("Hello".getBytes("UTF-8"));
  4. output.close();
  5. }

3.3、close

在操作完之后,InputStream和OutputStream都需要通过close()来关闭流,之后OS会释放底层资源。

3.3°、flush

只用于OutputStream,目的是将buffer内容真正输出到目的地。

因为写的时候,出于效率考虑,OS不是每次直接把1 byte写入文件或发送到网络,而是先放到内存buffer(本质上是byte [ ]数组),等到buffer写满,再一次性写入文件或网络。

对所有IO设备来说,一次写1B或1000B,花费的时间几乎相同,所以OutputStream有flush()方法,能强制把buffer内容输出。

调用时机

通常情况下,我们不需要调用这个flush(),因为①buffer写满了OutputStream会自动调用它;②调用close()关闭OutputStream之前,也会自动调用flush()方法。

但是某些时机我们需要手动调用flush(),比如在实现一个即时通讯软件时,用户发一句就要flush一句,而不能等待buffer满。

InputStream buffer

InputStream也有buffer。当从FileInputStream读取1 byte时,OS往往会一次性读取多个 bytes到buffer,read时直接返回buffer中的byte,而不是每次都IO 1 byte。

3.4、IOException

读写IO流时,可能发生错误,例如文件不存在、权限异常,它们由JVM封装为IOException抛出。

因此,所有与IO相关的代码都必须处理IOException。

实际使用时,为了避免读取时发生IO错误,IO流无法正确关闭,资源也无法及时释放,所以我们要用try...finally来保证IO流正确关闭:

  1. public void readFile() throws IOException {
  2. InputStream input = null;
  3. try {
  4. input = new FileInputStream("src/readme.txt");
  5. int n;
  6. while ((n = input.read()) != -1) {
  7. System.out.println(n);
  8. }
  9. } finally {
  10. if (input != null) {
  11. input.close();
  12. }
  13. }
  14. }

用try...finally来编写会感觉复杂,更好的写法是利用Java 7引入新的try(resource)语法,只需要编写try语法,就能让编译器自动为我们关闭资源。推荐写法如下:

  1. //InputStream
  2. public void readFile() throws IOException{
  3. try(InputStream input = new FileInputStream("src/readme.txt")){
  4. int n;
  5. while((n=input.read())!=-1)
  6. System.out.println(n);
  7. }//编译器在此自动为我们写入finally并调用close()
  8. }
  9.  
  10. //OutputStream
  11. public void writeFile() throws IOException{
  12. try(OutputStream output = new FileOutputStream("out/readme.txt")){
  13.   output.write("Hello".getBytes("UTF-8"));//Hello
  14. }
  15. }

同时操作多个资源时,在try(resource){ ... }中可以同时写出多个资源,用;隔开。例如同时读写两个文件:

  1. //读取input.txt,写入output.txt
  2. try(InputStream input = new FileInputStream("input.txt");
  3. OutputStream output = new FileOutputStream("output.txt")){
  4. input.transferTo(output);
  5. }

不过实际上,编译器并不会特别为InputStream加上自动关闭。只看resource是否实现了java.lang.AutoCloseable接口,如果实现了,就自动加上finally并调用close()方法。InputStream、OutputStream都实现了这个接口,因此都可以用在try( resoucrce )中。

4、缓冲

IO流中,每次用read()、write()读写1 byte未免太麻烦了。IO流各提供了两个重载方法来支持读写多个字节:

  • read( byte[ ] b ):从输入流中读取一定数量的bytes,并将之存入缓冲数组b中;
  • read( byte[ ] b , int off , int len ):从输出流中off byte处开始读取len bytes到缓冲数组b中;
  • write( byte[ ] b ):将b中的所有byte写入输出流中;
  • write( byte[ ] b , int off , int len ):从b中的off处开始,写入len bytes到输出流中。

利用read方法一次读取多个bytes时,需要先定义一个byte[ ]作为buffer,read会尽可能多的读取byte到buffer,但不会超过buffer大小。read返回实际读取的byte数,如果返回-1,表示没有更多的数据了。

4.1、read

用buffer一次读取多个bytes的代码如下:

  1. public void readFile() throws IOException{
  2. try(InputStream input = new FileInputStream("src/readme.txt")){
  3. byte[] buffer = new byte[1000];
  4. int n;
  5. while((n=input.read(buffer))!=-1)//读取到buffer
  6. System.out.println("read "+n+" bytes.");
  7. }
  8. }

5、阻塞

之前我们说过java.io是同步io,在进行IO时,会中断程序运行,直到数据IO完毕——此之谓阻塞。

6、其他InputStream实现类

用FileInputStream可以从文件获取输入流,这是InputStream常用的一个实现类。

6.1、ByteArrayInputStream

在内存中模拟一个InputStream:

  1. public class Main {
  2. public static void main(String[] args) throws IOException {
  3. byte [] data ={ 72, 101, 108, 108, 111, 33 };
  4. try(InputStream input = new ByteArrayInputStream(data)){
  5. int n;
  6. while((n=input.read())!=-1)
  7. System.out.println((char)n);
  8. }
  9. }
  10. }

ByteArrayInputStream实际上是把一个byte[ ]数组在内存中变成一个InputStream,虽然应用不多,但测试时可以用来构造一个InputStream。

7、其他OutputStream实现类

7.1、ByteArrayOutputStream

在内存中模拟一个OutputStream:

  1. public class Main {
  2. public static void main(String[] args) throws IOException {
  3. byte[] data;
  4. try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
  5. output.write("Hello".getBytes("UTF-8"));
  6. output.write("world!".getBytes("UTF-8"));
  7. data = output.toByteArray();
  8. }
  9. System.out.println(new String(data, "UTF-8"));
  10. }
  11. }

8、总结

1、InputStream、OutputStream是最基本的IO流,它传输的数据基本单位是byte;

常用的方法有:

  • intread():读取输入流的下一个byte,返回该byte表示的int值(0~255)。读到末尾,返回-1表示不能继续读了。
  • read( byte[ ] b ):从输入流中读取多个bytes,并将之存入缓冲数组b[ ]中;
  • read( byte[ ] b , int off , int len ):从输出流中off byte处开始读取len bytes到缓冲数组b中;
  • void write( int b ):写一个byte到输出流。虽然传入的是int,但只会写入1 byte,即该int的最低8位表示字节的部分( b & 0xff )
  • write( byte[ ] b ):将b中的所有byte写入输出流中;
  • write( byte[ ] b , int off , int len ):从b中的off处开始,写入len bytes到输出流中。

常见实现类有:

  • FileXXXStream:文件读写;
  • ByteArrayXXXStream:在内存中模拟IO流。

2、用法

  1. //InputStream
    public void readFile() throws IOException{
  2. try(InputStream input = new FileInputStream("src/readme.txt")){
  3. byte[] buffer = new byte[1000];
  4. int n;
  5. while((n=input.read(buffer))!=-1)//读取到buffer
  6. System.out.println("read "+n+" bytes.");
  7. }
  8. }
  1. //OutputStream
  2. public void writeFile() throws IOException{
  3. try(OutputStream output = new FileOutputStream("out/readme.txt")){
  4.   output.write("Hello".getBytes("UTF-8"));//Hello
  5. }
  6. }

也可以把InputStream和OutputStream资源的创建放在一起:

  1. //读取input.txt,写入output.txt
  2. try(InputStream input = new FileInputStream("input.txt");
  3. OutputStream output = new FileOutputStream("output.txt")){
  4. input.transferTo(output);
  5. }

Java:IO流(二)——InputStream/OutputStream具体用法:FileXXXStream、ByteArrayXXXStream的更多相关文章

  1. Java IO流(二)

    目录 字节缓冲流 概述 BufferedOutputStream类 继承父类的共性成员方法 构造方法 BufferedInputStream类 继承自父类的方法: 构造方法 文件复制练习(增强版 使用 ...

  2. Java IO流 FileOutputStream、FileInputStream的用法

    FileOutputStream.FileInputStream的使用 FileOutputStream是OutputStream的继承类,它的主要功能就是向磁盘上写文件.FileOutputStre ...

  3. Java IO流 FileOutputStream、FileInputStream的用法   

    FileOutputStream.FileInputStream的使用 FileOutputStream是OutputStream的继承类,它的主要功能就是向磁盘上写文件.FileOutputStre ...

  4. Java IO流操作汇总: inputStream 和 outputStream【转】

    我们在进行Android java 开发的时候,经常会遇到各种IO流操作.IO流操作一般分为两类:字符流和字节流.以“Reader”结尾都是字符流,操作的都是字符型的数据:以“Stream”结尾的都是 ...

  5. 《二》Java IO 流的分类介绍

    一.根据流向分为输入流和输出流: 注意输入流和输出流是相对于程序而言的. 输出:把程序(内存)中的内容输出到磁盘.光盘等存储设备中        输入:读取外部数据(磁盘.光盘等存储设备的数据)到程序 ...

  6. Java IO流详解(二)——File类

    在上一章博客中简单的介绍了Java IO流的一些特征.也就是对文件的输入输出,既然至始至终都离不开文件,所以Java IO流的使用得从File这个类讲起. File类的描述:File类是文件和目录路径 ...

  7. Java IO流题库

    一.    填空题 Java IO流可以分为   节点流   和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...

  8. JAVA.IO流学习笔记

    一.java.io 的描述 通过数据流.序列化和文件系统提供系统输入和输出.IO流用来处理设备之间的数据传输 二.流 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数 ...

  9. 【Java基础】Java IO流的总结

    Java IO流分为输入流和输出流,而输入流和输出流中又分字符流和字节流.顾名思义,输入流则是输入到程序中计算,输出流是把程序的结果输出到文件或者设备.而字符流输入输出以字符为单位,字节流则是以字节为 ...

  10. Java IO流学习总结八:Commons IO 2.5-IOUtils

    Java IO流学习总结八:Commons IO 2.5-IOUtils 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/550519 ...

随机推荐

  1. 源码分析axios(1)~源码分析、模拟axios的创建

    ■ 查看源码发现,起初axios[instance=bind(Axios.prototype.request, context);]是一个函数, 但后续[ utils.extend(instance, ...

  2. 【重构前端知识体系之HTML】HTML5给网页音频带来的变化

    [重构前端知识体系之HTML]HTML5给网页音频带来的变化 引言 音乐播放,相信大家都很熟悉,但是早在之前的音乐播放之前,你的浏览器会问你,是否下载flash插件.然而现在,估计一些年轻的开发者都不 ...

  3. 函数的参数python教程

    一:函数 什么是函数? 函数就类似于工具 提前定义之后可以反复使用 代码冗余 结构清晰 修改繁杂等问题 二:函数的语法结构 def 函数名(参数1,参数2) '''函数注释''' 函数体代码 retu ...

  4. 添加项目文件时候不要把引用文件直接放到bin-debug里

    如果时anycpu没问题,但是新建其他平台时,会重新生成失败,原因时无法找到dll,现象为x64目录下的debug文件夹为空

  5. 「YNOI2016」自己的发明

    「YNOI2016」自己的发明 不换根 基本的莫队吧... 子树直接转到dfs序上. 其余部分可以见 「SNOI2017」一个简单的询问. 换根 根root,查询x,分3种: root不在x子树内,按 ...

  6. UIView与核心动画对比?

    1.UIView和核心动画区别?        核心动画只能添加到CALayer        核心动画一切都是假象,并不会改变真实的值.             2.什么时候使用UIView的动画? ...

  7. linux计划任务之cron

    目录 cron计划任务之用户级 cron计划任务之系统级 cron计划任务之用户级 1.安装crond centos7 执行命令: # yum install -y crontabs /bin/sys ...

  8. js表达式和语句

    表达式 一个表达式可以产生一个值,有可能是运算.函数调用.有可能是字面量.表达式可以放在任何需要值的地方. 语句 语句可以理解为一个行为,循环语句和判断语句就是典型的语句.一个程序有很多个语句组成,一 ...

  9. 解析视频真实地址播放 By HL

    手思3.0启动,从手思1.0版的iOS2个人,到现在的N个人,如今又回来做手思了. 重新做自然就要比之前的更好,更强大,而视频播放页的效果相当的不乐观. 公司用的是优酷的视频连接,只能用webview ...

  10. UITextView模拟UITextField 设置Placeholder属性 --董鑫

    由于最近有用到输入框,刚开始考虑的是UITextField,因为它在没有输入的时候可以有提示的Placeholder更能,很人性化,但UITextField只能单行输入,不能跳行,对于一些强迫症的亲来 ...