`
0428loveyu
  • 浏览: 28536 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

Java I/O (2): OutputStream分析

 
阅读更多

在Java I/O中,抽象类OutputStream是其他输出流类(如FileOutputStream)的基础类,分析一下这个类的源码很有必要。

概要

这个抽象类实现了两个接口:Closeable和Flushable。需要注意的是,在这个类的API中写到这个抽象了实现了三个接口,还包括AutoCloseable,这是因为Closeable接口继承了AutoCloseable接口的缘故。类定义如下:
public abstract class OutputStream implements Closeable, Flushable

该类使用默认的构造函数,没有参数。类中定义了1个抽象方法和4个具体方法,其中close()和flush()是对接口中方法的实现(其实是空实现,什么都没有)。方法声明分别如下:
    public abstract void write(int b) throws IOException;

    public void write(byte b[]) throws IOException

    public void write(byte b[], int off, int len) throws IOException 

以上三个方法都是用于写出字节,具体请看下文。还有两个空实现的方法:
    public void flush() throws IOException {
    }
    public void close() throws IOException {
    }


方法分析

下面是对各个方法的分析,先来看write(int b)

write(int b)

这是唯一一个抽象方法,子类中必须提供具体的实现。这个方法写出一个字节到输出流中。仔细看一下参数,发现是int类型,也就是有4个字节,那是如何处理的呢?很容易想到,只取低8位,也就意味这int的取值范围为0-255.如果提供一个超出这个范围的参数,将自动把高的24位去掉,具体地说,如果给定一个b超出范围,则将b除以256取模。例如,传递一个256,实际上写入的是1。将这个值写入输出流之后,输出流的另一端如何解析,取决于另一端。例如,对于控制台,是将其转换成ASCII码输出。子类必须实现这一方法,例如,FileOutputStream就调用本地方法来实现这个方法。如果写出过程遇到错误,抛出IOException,例如说,这个流已经被关闭,则抛出这个异常。

write(byte b[], int off, int len)

上一个方法一次只写入一个字节,许多时候是不方便的,这个方法则写入data字节数组中的len字节到输出流。参数中data就是待写入的字节(不一定全部写入),从第offset位开始写入,off+len-1是最后一位被写入的。在OutputStream这个抽象类中,直接循环调用write(int b)方法,如下:
if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }

API鼓励子类提供更高性能的实现方法。在这个方法中,由于字节本身就是8位,没有超出范围的情况,所以直接写入无需转换。如果传递的data为空,则抛出NullPointerException异常。如果被写入的部分超出字节数组范围,抛出IndexOutofBoundsException异常。具体地说,有以下5中情况,也就是if语句当中的5个表达式。除此之外,如果写入过程出现错误,一样抛出IOException。

write(byte b[])

这个方法其实是上一个方法的特殊情况,当off=0, len=data.length的时候,就得到了这个方法。具体实现也是通过调用上个方法来实现的,如下:
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

有一点需要说明,如果一次写入的字节数组太大,可能就会是性能下降,至于多少合适,得根据具体情况而定。比如写入网络的时候就需要小一点了,如128字节。写入文件的话,稍大一点1024.

flush()

这个方法是对Flushable接口的实现。如果在写出方法的具体实现中,用到了缓冲机制。则这个方法用于将缓冲区的数据“冲刷”到目的地去。这里需要特别理解,如果写出的方法用到了操作系统层的抽象,比如说FileOutputStream,那么该方法只能保证将缓冲区的数据提交给操作系统,但是不能保证数据被写入到磁盘文件中去。如果冲刷过程出现I/O 错误,抛出IOException。OutputStream类中的方法什么都不做。当输出流被关闭或者程序退出的时候,缓冲区的数据互自动被冲刷。对于System.out、System.err这样的输出流,当调用println()方法或者遇到换行符‘\n’的时候,缓冲数据自动被冲刷。当然,你可以在PrintStream的构造函数中传递参数来设置是否自动冲刷。

close()

这是对Closeable接口中close方法的实现。用于关闭输出流,释放相关的系统资源(如文件句柄(file handle)或者网络端口)。关闭之后,该输出流不能再被操作或者重新打开,否则抛出异常。当然,你可以不关闭,但是这不是一个好习惯,时常会出现严重问题。比如你打开文件,正在操作,那你不关闭,其他线程可能就会一直阻塞下去了。可以如下关闭输出流:
try {
  OutputStream out = new FileOutputStream("numbers.dat");
  // Write to the stream...
  out.close( );
}
catch (IOException ex) {
  System.err.println(ex);
}

当然,这样有个问题,如果在写入的时候出现异常,那么输出流的close方法就不会被执行,也就是不会被关闭。换一种方法;
OutputStream out = null;
try {
  out = new FileOutputStream("numbers.dat");
  // Write to the stream...
}
catch (IOException ex) {
  System.err.println(ex);
}
finally {
  if (out != null) {
    try {
      out.close( );
    }
    catch (IOException ex) {
      System.err.println(ex);
    }
  }
}

注意到,这里的OutputStream声明放到了try语句外面,必须这样才能被finally中的语句访问。这样写虽然安全,但是有点丑陋就是了。如果不处理异常而是抛出,那么可以这样:
OutputStream out == null;
try {
  out = new FileOutputStream("numbers.dat");
  // Write to the stream...
}
finally {
  if (out != null) out.close( );
}

一个自定义子类

OutputStream的子类至少要重写write(int b)方法,当然,有些子类把所有方法都重写或者重写一部分。下面这个例子写入的时候什么都不敢,只是提供一个实现参考:
完整代码如下:
import java.io.*;
public class NullOutputStream extends OutputStream {
  private boolean closed = false;
  public void write(int b) throws IOException {
    if (closed) throw new IOException("Write to closed stream");
  }
  public void write(byte[] data, int offset, int length)
   throws IOException {
    if (data == null) throw new NullPointerException("data is null");
    if (closed) throw new IOException("Write to closed stream");
  }
  public void close( ) {
    closed = true;
  }
}

这个类重写了出了flush以外的四个方法,因为写入方法什么都不干,当然没必须flush啦。实现很容易懂。不多说明。




分享到:
评论

相关推荐

    Java I/O总结

    Java I/O总结  从new BufferedReader(new InputStreamReader(conn.getInputStream()))想到的 ... Java I/O总结——OutputStream  Java I/O总结——Reader  Java I/O总结——Writer  Java I/O总结——补充说明

    Java I/O 使用和最佳实践

    Java 中的 I/O 类由一组抽象类和接口组成,这些类和接口协同工作,使 Java 应用程序能够读取和写入数据。其中包括 File、InputStream、OutputStream、Reader、Writer 等类和接口。您可以使用这些类和接口来创建文件...

    Java_IO详细教程

    从new BufferedReader(new InputStreamReader(conn.getInputStream()))想到的 ... Java I/O总结——OutputStream  Java I/O总结——Reader  Java I/O总结——Writer  Java I/O总结——补充说明

    Java IO.pdf

    一、概览 Java 的 I/O 大概可以分成以下几类: 磁盘操作:File 字节操作:InputStream 和 OutputStream 字符操作:Reader 和 Writer 对象操作:Serializable 网络操作:Socket 新的输入/输出:NIO

    java_I/ODemo

    对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务,在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是...

    lab-2-Alex-PtGa:GitHub Classroom创建的lab-2-Alex-PtGa

    2号实验室工作 在“ DEV-J120。Java SE。Standard软件包”课程中 研究课题 例外情况: 引起特殊情况; 异常处理; 使用标准排除项。 流I / O: 释放资源: AutoClosable界面 Closable界面 try-with-resources...

    ava支持的zip压缩和解压缩

    Java I/O类库还收录了一些能读写压缩格式流的类。要想提供压缩功能,只要把它们包在已有的I/O类的外面就行了。这些类不是Reader和Writer,而是InputStream和OutStreamput的子类。这是因为压缩算法是针对byte而不是...

    基础深化和提高-IO流技术学习大全

    Java的I/O流(Input/Output Stream)技术是Java编程中用于处理输入和输出的重要部分。它提供了一种灵活而统一的方式来与文件、网络连接、内存等进行数据交换。 I/O流主要分为两种类型:字节流和字符流。 字节流: ...

    使用Buffer进行II/O操作

    使用缓冲组件对文件I/O进行包装,可以有效的提升文件的I/O性能。

    跟汤老师学Java(第15季):I/O输入输出流

    本课程从零开始,以通俗易懂的方式讲解Java技术,手把手教你掌握每一个知识点。 真正做到零基础入门学习,适合初学者的教程! 课程内容包括: 1.File类 2.IO流简介 3.流的分类  输入流、输出流  字节流、字符...

    Java性能优化之使用NIO提升性能(Buffer和Channel)

    在Java的标准I/O中,提供了基于流的I/O实现,即InputStream和OutputStream。这种基于流的实现以字节为单位处理数据,并且非常容易建立各种过滤器。NIO是NewI/O的简称,具有以下特性:为所有的原始类型提供(Buffer)...

    关于编码问题的深度解析

    编码问题的产生其实都是I/O操作导致的问题,也就是说所有I/O存在的地方就有可能会出现编码问题。所以要想深度解析编码问题,我们就必须回到源码的实现机制...看I/O(以Java的I/O为例)的底层图:读操作:写操作:也就是说

    jsr80 java 访问 usb

    usb.util : 这个包提供了一些有用的实用程序,可以将 firmware下载到 USB 设备上、将 USB 系统的内容转储到 XML 中、以及将只有 bulk I/O 的 USB 设备工具转换成一个套接字(socket)。 usb.devices : 这个可选包收集...

    java基础核心总结归纳---参考手册--心得手册-学习资料-总结经验

    I/O 24 File 类 24 基础 IO 类和相关⽅法 25 InputStream 25 OutputStream 25 Reader 类 26 Writer 类 26 InputStream 及其⼦类 27 OutputStream 及其⼦类 27 Reader 及其⼦类 28 Writer 及其⼦类 28 注解 28 关于 ...

    Java 基础核心总结 +经典算法大全.rar

    I/O File 类 基础 IO 类和相关方法InputStream OutputStream Reader 类Writer 类 InputStream 及其子类 OutputStream 及其子类Reader 及其子类Writer 及其子类 注解 关于 null 的几种处理方式大小写敏感 null 是...

    java流详细介绍

    java流详细介绍,inputstream,outputstream,reader,writer。

    java初学者必看

    第14章 Java I/O系统 14.1 I/O概述 14.2 文件操作 14.2.1 File类 14.2.2 File类应用 14.2.3 RandomAccessFile类 14.2.4 RandomAccessFile应用 14.3 字节流InputStream、OutputStream 14.3.1 字节输入、输出...

    javaweb数据写入到excel

    System.out.println("jxl write file i/o exception!, cause by: "+e.getMessage()); } } private void putRow(WritableSheet ws, int rowNum, Object[] cells) throws RowsExceededException, WriteException ...

    PDF转换(DOC、DOCX、PPT 、PPTX、ODT)

    java -jar doc-converter.jar -i test.ppt -o ~\output.pdf java -jar doc-converter.jar -i ~\no-extension-file -o ~\output.pdf -t docx 接口调用: 实现DocxToPDFConverter, PptToPDFConverter, ...

Global site tag (gtag.js) - Google Analytics