JAVA篇:Java IO (二)抽象基类InputStream、OutputStream、Reader、Writer

2、抽象基类InputStream、OutputStream、Reader、Writer

IO流的抽象基类分字节输入流(InputStream)、字节输出流(OutputStream)、字符输入流(Reader)、字符输出流(Writer)。它们是IO流中的抽象父类,是Java IO操作的基础。流都实现了Closeable接口,即都需要关闭,输出流则额外实现了一个Flushable方法,主要是通知立刻将数据刷入指定输出位置。

2.1 InputStream

java.io.InputStream是一个抽象类,是字节输入流的所有类的超类,除了继承自Object的属性和方法,InputStream包含9个方法:

  1. abstract int read()方法是一个虚拟方法,从输入流中读取下一个字节,其子类必须实现这个方法

  2. int read(byte[] b,int off,int len)方法将流读入byte[]数组中第off个位置开始,读取len个字节。其实现有调用read()方法进行读取,读取前判断参数是否合理,若读取到-1则退出(流以-1判断是否结束),并返回已经读取的数据个数,若读取的个数为0则返回-1。

    public int read(byte b[], int off, int len) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if (off < 0 || len < 0 || len > b.length - off) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
    ​
            int c = read();
            if (c == -1) {
                return -1;
            }
            b[off] = (byte)c;
    ​
            int i = 1;
            try {
                for (; i < len ; i++) {
                    c = read();
                    if (c == -1) {
                        break;
                    }
                    b[off + i] = (byte)c;
                }
            } catch (IOException ee) {
            }
            return i;
        }

     

     

  3. int read(byte[])方法用处是将流的输入读入byte[]数组中,其实际上调用的是read(byte[],int,int)

  4. long skip(long),跳过指定个字节不读。其具体实现是:创建了一个跳过的缓冲数据,将读到这里面去,跳过的字节有长度限制,为2048个。通过循环排除IO异常的感染,知道读完或者读满要跳过的,然后返回实际跳过的量。

      
     public long skip(long n) throws IOException {
    ​
            long remaining = n;
            int nr;
    ​
            if (n <= 0) {
                return 0;
            }
    ​
            int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
            byte[] skipBuffer = new byte[size];
            while (remaining > 0) {
                nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
                if (nr < 0) {
                    break;
                }
                remaining -= nr;
            }
    ​
            return n - remaining;
        }

     

  5. int available()返回估测的可读的数量,在InputStream中是直接return 0。这个方法对于所有流的实现来说不都是准确的,所以慎用。这个方法需要被子类覆写。单次读或跳过很多字节不会阻塞,但是可能会读取或跳过少量字节。

  6. void close(),关闭流,但是在InputStream中没有具体实现,会释放操作系统资源。

  7. synchronized void mark(int readlimit)标记读取位置,如果流实现支持,就可以重置位置,下次读取则一模一样。InputStream中什么都没做。使用之前要通过markSupported方法判断一下是否支持。

  8. synchronized void reset()reset到mark方法最后一次调用的位置,InputStream中并没有实现mark方法,所以reset方法直接抛出异常。

  9. boolean markSupported()判断当前流是否支持标记流。

2.2 OutputStream

java.io.OutputStream此抽象类是表示输出字节流的所有类的超累,输出流接受输出字节并将这些字节发送到某个接收器,除了继承自Object的属性和方法,OutputStream包含5个方法:

  1. abstract void write(int b),抽象方法,通常是写入一个字节byte,低8位将写入,高24位会被忽略。将指定字节写入输出位置,子类必须实现这个方法。

  2. void write(byte b[], int off, int len)方法,将数组b的起始位置off开始,写入len长度的字节。其实现包含边界判定,最后通过循环调用write方法实现。

        
    public void write(byte b[], int off, int len) throws IOException {
            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]);
            }
        }

     

     

  3. void write(byte b[])通过调用方法2:write(b,0,b.length)实现

  4. void flush()刷新此输出流并强制携出所有缓冲的输出字节。flush的常规协定是:如果此输出流的实现已经缓冲了以前写入的任何字节,则调用flush方法指示应将这些字节立即写入它们的预期目标。但是如果此流的预期目标是由基础操作系统提供的一个抽象(如一个文件),则flush只能保证将以前写入到流的字节传递给操作系统进行写入,不保证能立即将这些字节写入到物理设备(如磁盘驱动器)。在OutputStream中该方法不执行任何操作。

  5. void close()关闭输出流并释放与此流有关的所有系统资源。close的常规协定是:该方法将关闭输出流,关闭的流不能执行输出操作,也不能重新发开。OutputStream的close方法不执行人格操作。

2.3 Reader

java.io.Reader实现了接口Closeable和Readable,其是用于读取字符流的抽象类。

相比于字节输入流InputStream,Reader中不同的有以下几点:

  1. lock对象 lock是Object类型的对象,用于同步针对此流的操作的对象。为了提高效率,字符流可以使用自身以外的对象来保护重要部分,因此,子类应使用此字段中的对象而不是this或者同步的方法。构造方法中Reader()所做的是创建一个新的字符流,其重要部分将同步其自身的reader;而Reader(Object lock)则是创建一个新的字符流reader,其重要部分将同步给定的对象。

  2. Reader的三个read方法中,read()方法和read(char cbuf[])都是使用read(char cbuf[], int off, int len)实现的,而子类必须实现read(char cbuf[], int off, int len)方法,注意:用于支持高效单字符输入的子类必须重写read()方法

       /*用于支持高效单字符输入的子类必须重写该方法*/
       public int read() throws IOException {
            char cb[] = new char[1];
            if (read(cb, 0, 1) == -1)
                return -1;
            else
                return cb[0];
        }
    ​
        public int read(char cbuf[]) throws IOException {
            return read(cbuf, 0, cbuf.length);
        }
    ​
        /*子类必须实现该方法*/
        abstract public int read(char cbuf[], int off, int len) throws IOException;

     

     

  3. read(CharBuffer target)方法:该方法试图将字符读入指定的字符缓冲区。缓冲区可照鸳鸯用作字符的存储库:所做的唯一改变时put操作的结果。不对缓冲区执行翻转或重绕操作。

      
     public int read(java.nio.CharBuffer target) throws IOException {
            int len = target.remaining();
            char[] cbuf = new char[len];
            int n = read(cbuf, 0, len);
            if (n > 0)
                target.put(cbuf, 0, n);
            return n;
        }

     

     

  4. *ready()方法** 该方法在Reader中是直接返回flase的,其用来判断是否准备读取此流。如果保证下一个read()不阻塞输入,则返回True,否则返回false。注意,返回false并不保证下一次读取。

  5. skip()方法的长度限制是8192

2.4 Writer

java.io.Writer实现了Closeable, Flushable, Appendable三个接口,它时写入字符流的抽象类。

Appendable:如果某个类的实例打算接收取自 Formatter 的格式化输出,那么该类必须实现 Appendable 接口。

Writer相比于字节输出流OutputStream有更多的不同。

  1. lock对象

  2. write方法 Writer提供了5个write方法,其中子类需要实现的是void write(char cbuf[], int off, int len)

    /*该方法使用write(char cbuf[], int off, int len)方法实现*/
     public void write(int c) throws IOException {
          synchronized (lock) {
              if (writeBuffer == null){
                  writeBuffer = new char[WRITE_BUFFER_SIZE];
              }
              writeBuffer[0] = (char) c;
              write(writeBuffer, 0, 1);
          }
      }
      /*该方法使用write(char cbuf[], int off, int len)方法实现*/
      public void write(char cbuf[]) throws IOException {
          write(cbuf, 0, cbuf.length);
      }
    ​
      /*子类必须实现该方法*/
      abstract public void write(char cbuf[], int off, int len) throws IOException;
      /*该方法使用write(String str, int off, int len)方法实现*/
      public void write(String str) throws IOException {
          write(str, 0, str.length());
      }
    ​
      /*该方法使用write(char cbuf[], int off, int len)方法实现*/
      public void write(String str, int off, int len) throws IOException {
          synchronized (lock) {
              char cbuf[];
              if (len <= WRITE_BUFFER_SIZE) {
                  if (writeBuffer == null) {
                      writeBuffer = new char[WRITE_BUFFER_SIZE];
                  }
                  cbuf = writeBuffer;
              } else {    // Don't permanently allocate very large buffers.
                  cbuf = new char[len];
              }
              str.getChars(off, (off + len), cbuf, 0);
              write(cbuf, 0, len);
          }
      }

     

    3.append方法都来自于其实现的Appendable接口,用于将指定字符或字符序列添加到此writer。
  3.    public Writer append(CharSequence csq) throws IOException {
            if (csq == null)
                write("null");
            else
                write(csq.toString());
            return this;
        }
    ​
        
        public Writer append(CharSequence csq, int start, int end) throws IOException {
            CharSequence cs = (csq == null ? "null" : csq);
            write(cs.subSequence(start, end).toString());
            return this;
        }
    ​
       
        public Writer append(char c) throws IOException {
            write(c);
            return this;
        }

     


 

posted @ 2021-06-26 16:04  l.w.x  阅读(887)  评论(0编辑  收藏  举报