zoukankan      html  css  js  c++  java
  • java io系列18之 CharArrayReader(字符数组输入流)

    从本章开始,我们开始对java io中的“字符流”进行学习。首先,要学习的是CharArrayReader。学习时,我们先对CharArrayReader有个大致了解,然后深入了解一下它的源码,最后通过示例来掌握它的用法。

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_18.html

    CharArrayReader 介绍

    CharArrayReader 是字符数组输入流。它和ByteArrayInputStream类似,只不过ByteArrayInputStream是字节数组输入流,而CharArray是字符数组输入流。CharArrayReader 是用于读取字符数组,它继承于Reader。操作的数据是以字符为单位!


    CharArrayReader 函数列表

    复制代码
    CharArrayReader(char[] buf)
    CharArrayReader(char[] buf, int offset, int length)
    
    void      close()
    void      mark(int readLimit)
    boolean   markSupported()
    int       read()
    int       read(char[] buffer, int offset, int len)
    boolean   ready()
    void      reset()
    long      skip(long charCount)
    复制代码

    Reader和CharArrayReader源码分析

    Reader是CharArrayReader的父类,我们先看看Reader的源码,然后再学CharArrayReader的源码。

    1. Reader源码分析(基于jdk1.7.40)

    复制代码
     1 package java.io;
     2 
     3 public abstract class Reader implements Readable, Closeable {
     4 
     5     protected Object lock;
     6 
     7     protected Reader() {
     8         this.lock = this;
     9     }
    10 
    11     protected Reader(Object lock) {
    12         if (lock == null) {
    13             throw new NullPointerException();
    14         }
    15         this.lock = lock;
    16     }
    17 
    18     public int read(java.nio.CharBuffer target) throws IOException {
    19         int len = target.remaining();
    20         char[] cbuf = new char[len];
    21         int n = read(cbuf, 0, len);
    22         if (n > 0)
    23             target.put(cbuf, 0, n);
    24         return n;
    25     }
    26 
    27     public int read() throws IOException {
    28         char cb[] = new char[1];
    29         if (read(cb, 0, 1) == -1)
    30             return -1;
    31         else
    32             return cb[0];
    33     }
    34 
    35     public int read(char cbuf[]) throws IOException {
    36         return read(cbuf, 0, cbuf.length);
    37     }
    38 
    39     abstract public int read(char cbuf[], int off, int len) throws IOException;
    40 
    41     private static final int maxSkipBufferSize = 8192;
    42 
    43     private char skipBuffer[] = null;
    44 
    45     public long skip(long n) throws IOException {
    46         if (n < 0L)
    47             throw new IllegalArgumentException("skip value is negative");
    48         int nn = (int) Math.min(n, maxSkipBufferSize);
    49         synchronized (lock) {
    50             if ((skipBuffer == null) || (skipBuffer.length < nn))
    51                 skipBuffer = new char[nn];
    52             long r = n;
    53             while (r > 0) {
    54                 int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
    55                 if (nc == -1)
    56                     break;
    57                 r -= nc;
    58             }
    59             return n - r;
    60         }
    61     }
    62 
    63     public boolean ready() throws IOException {
    64         return false;
    65     }
    66 
    67     public boolean markSupported() {
    68         return false;
    69     }
    70 
    71     public void mark(int readAheadLimit) throws IOException {
    72         throw new IOException("mark() not supported");
    73     }
    74 
    75     public void reset() throws IOException {
    76         throw new IOException("reset() not supported");
    77     }
    78 
    79      abstract public void close() throws IOException;
    80 }
    复制代码

    2. CharArrayReader 源码分析(基于jdk1.7.40)

    复制代码
      1 package java.io;
      2 
      3 public class CharArrayReader extends Reader {
      4     // 字符数组缓冲
      5     protected char buf[];
      6 
      7     // 下一个被获取的字符的位置
      8     protected int pos;
      9 
     10     // 被标记的位置
     11     protected int markedPos = 0;
     12 
     13     // 字符缓冲的长度
     14     protected int count;
     15 
     16     // 构造函数
     17     public CharArrayReader(char buf[]) {
     18         this.buf = buf;
     19         this.pos = 0;
     20         this.count = buf.length;
     21     }
     22 
     23     // 构造函数
     24     public CharArrayReader(char buf[], int offset, int length) {
     25         if ((offset < 0) || (offset > buf.length) || (length < 0) ||
     26             ((offset + length) < 0)) {
     27             throw new IllegalArgumentException();
     28         }
     29         this.buf = buf;
     30         this.pos = offset;
     31         this.count = Math.min(offset + length, buf.length);
     32         this.markedPos = offset;
     33     }
     34 
     35     // 判断“CharArrayReader是否有效”。
     36     // 若字符缓冲为null,则认为其无效。
     37     private void ensureOpen() throws IOException {
     38         if (buf == null)
     39             throw new IOException("Stream closed");
     40     }
     41 
     42     // 读取下一个字符。即返回字符缓冲区中下一位置的值。
     43     // 注意:读取的是字符!
     44     public int read() throws IOException {
     45         synchronized (lock) {
     46             ensureOpen();
     47             if (pos >= count)
     48                 return -1;
     49             else
     50                 return buf[pos++];
     51         }
     52     }
     53 
     54     // 读取数据,并保存到字符数组b中从off开始的位置中,len是读取长度。
     55     public int read(char b[], int off, int len) throws IOException {
     56         synchronized (lock) {
     57             ensureOpen();
     58             if ((off < 0) || (off > b.length) || (len < 0) ||
     59                 ((off + len) > b.length) || ((off + len) < 0)) {
     60                 throw new IndexOutOfBoundsException();
     61             } else if (len == 0) {
     62                 return 0;
     63             }
     64 
     65             if (pos >= count) {
     66                 return -1;
     67             }
     68             if (pos + len > count) {
     69                 len = count - pos;
     70             }
     71             if (len <= 0) {
     72                 return 0;
     73             }
     74             System.arraycopy(buf, pos, b, off, len);
     75             pos += len;
     76             return len;
     77         }
     78     }
     79 
     80     // 跳过n个字符
     81     public long skip(long n) throws IOException {
     82         synchronized (lock) {
     83             ensureOpen();
     84             if (pos + n > count) {
     85                 n = count - pos;
     86             }
     87             if (n < 0) {
     88                 return 0;
     89             }
     90             pos += n;
     91             return n;
     92         }
     93     }
     94 
     95     // 判断“是否能读取下一个字符”。能的话,返回true。
     96     public boolean ready() throws IOException {
     97         synchronized (lock) {
     98             ensureOpen();
     99             return (count - pos) > 0;
    100         }
    101     }
    102 
    103     public boolean markSupported() {
    104         return true;
    105     }
    106 
    107     // 保存当前位置。readAheadLimit在此处没有任何实际意义
    108     // mark()必须和reset()配合使用才有意义!
    109     public void mark(int readAheadLimit) throws IOException {
    110         synchronized (lock) {
    111             ensureOpen();
    112             markedPos = pos;
    113         }
    114     }
    115 
    116     // 重置“下一个读取位置”为“mark所标记的位置”
    117     public void reset() throws IOException {
    118         synchronized (lock) {
    119             ensureOpen();
    120             pos = markedPos;
    121         }
    122     }
    123 
    124     public void close() {
    125         buf = null;
    126     }
    127 }
    复制代码

    说明
    CharArrayReader实际上是通过“字符数组”去保存数据。

    (01) 通过 CharArrayReader(char[] buf) 或 CharArrayReader(char[] buf, int offset, int length) ,我们可以根据buf数组来创建CharArrayReader对象。
    (02) read()的作用是从CharArrayReader中“读取下一个字符”。
    (03) read(char[] buffer, int offset, int len)的作用是从CharArrayReader读取字符数据,并写入到字符数组buffer中。offset是将字符写入到buffer的起始位置,len是写入的字符的长度。
    (04) markSupported()是判断CharArrayReader是否支持“标记功能”。它始终返回true。
    (05) mark(int readlimit)的作用是记录标记位置。记录标记位置之后,某一时刻调用reset()则将“CharArrayReader下一个被读取的位置”重 置到“mark(int readlimit)所标记的位置”;也就是说,reset()之后再读取CharArrayReader时,是从mark(int readlimit)所标记的位置开始读取。

    示例代码

    关于CharArrayReader中API的详细用法,参考示例代码(CharArrayReaderTest.java): 

    复制代码
     1 /**
     2  * CharArrayReader 演示程序
     3  *
     4  * @author skywang
     5  */
     6 
     7 import java.io.CharArrayReader;
     8 import java.io.CharArrayWriter;
     9 import java.io.IOException;
    10 
    11 public class CharArrayReaderTest {
    12 
    13     private static final int LEN = 5;
    14     // 对应英文字母“abcdefghijklmnopqrstuvwxyz”
    15     private static final char[] ArrayLetters = new char[] {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    16     
    17     public static void main(String[] args) {
    18         tesCharArrayReader() ;
    19     }
    20 
    21     /**
    22      * CharArrayReader的API测试函数
    23      */
    24     private static void tesCharArrayReader() {
    25         try {
    26             // 创建CharArrayReader字符流,内容是ArrayLetters数组
    27             CharArrayReader car = new CharArrayReader(ArrayLetters);
    28 
    29             // 从字符数组流中读取5个字符
    30             for (int i=0; i<LEN; i++) {
    31                 // 若能继续读取下一个字符,则读取下一个字符
    32                 if (car.ready() == true) {
    33                     // 读取“字符流的下一个字符”
    34                     char tmp = (char)car.read();
    35                     System.out.printf("%d : %c
    ", i, tmp);
    36                 }
    37             }
    38 
    39             // 若“该字符流”不支持标记功能,则直接退出
    40             if (!car.markSupported()) {
    41                 System.out.println("make not supported!");
    42                 return ;
    43             }
    44 
    45             // 标记“字符流中下一个被读取的位置”。即--标记“f”,因为因为前面已经读取了5个字符,所以下一个被读取的位置是第6个字符”
    46             // (01), CharArrayReader类的mark(0)函数中的“参数0”是没有实际意义的。
    47             // (02), mark()与reset()是配套的,reset()会将“字符流中下一个被读取的位置”重置为“mark()中所保存的位置”
    48             car.mark(0);
    49 
    50             // 跳过5个字符。跳过5个字符后,字符流中下一个被读取的值应该是“k”。
    51             car.skip(5);
    52 
    53             // 从字符流中读取5个数据。即读取“klmno”
    54             char[] buf = new char[LEN];
    55             car.read(buf, 0, LEN);
    56             System.out.printf("buf=%s
    ", String.valueOf(buf));
    57         
    58             // 重置“字符流”:即,将“字符流中下一个被读取的位置”重置到“mark()所标记的位置”,即f。
    59             car.reset();
    60             // 从“重置后的字符流”中读取5个字符到buf中。即读取“fghij”
    61             car.read(buf, 0, LEN);
    62             System.out.printf("buf=%s
    ", String.valueOf(buf));
    63         } catch (IOException e) {
    64             e.printStackTrace();
    65         }
    66     }
    67 }
    复制代码

    运行结果

    0 : a
    1 : b
    2 : c
    3 : d
    4 : e
    buf=klmno
    buf=fghij

  • 相关阅读:
    Windows 窗体设计器中的设计时错误
    union all 里面的order by
    docx转doc时,防止公式被转成图片的解决办法
    学习方向推荐
    关于验收测试的几个困惑
    《实例化需求》读书笔记
    VS2010中使用 SpecFlow + Selenium.WebDriver
    敏捷团队成员应具备的素质
    Jolt Awards: The Best Books
    在Ajax.ActionLink的OnBegin,onComplete等事件中使用this【解决办法】
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/3844036.html
Copyright © 2011-2022 走看看