[重学Java基础][Java IO流][Part.7] 字符串输入输出流

[重学Java基础][Java IO流][Part.7] 字符串输入输出流

StringReader

概述

StringReader 字符输入流 和CharArrayReader类似 都是节点流 内存流
和CharArrayReader不同的地方是直接读入字符串而不是字符数组

用法也是类似的 都是用于接口适配 如果你需要调用的接口采用了Reader为参数
而你的数据源来自内存而不是其他外部数据源 ,那么就可以使用StringReader

源码分析

成员变量

和CharArrayReader相似

字符串内容体
private String str;
流内容长度
private int length;
索引游标 下一个流读入位置 
private int next = 0;
在流中被标记的位置
private int mark = 0;

成员方法

构造方法 很简单 传入一个String参数s 初始化成员变量即可

public StringReader(String s) {
    this.str = s;
    this.length = s.length();
}

读取字符方法 如果下一个读入位置已经超过了流内容长度 则返回-1表示已读取完毕
否则返回对应索引位置的字符对应的整型数值 并移动索引游标

public int read() throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (next >= length)
            return -1;
        return str.charAt(next++);
    }
}

读入字符 并写入到字符数组方法
入参为指定的要存储的内容的字符数组char cbuf[],数组存储起始的位置int off和终止位置int len

public int read(char cbuf[], int off, int len) throws IOException {
    synchronized (lock) {
        例行的安全检查 判断流是否开启 读入长度 起始终止位置是否越界
        ensureOpen();
        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
            ((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        如果索引游标超过数组长度 读取完毕 返回-1
        if (next >= length)
            return -1;
        整形值int n,设置为length-next和len之间的较小值,因为一般情况下使用len即可,
        如果len长度超过了数据的总长度,那么就要使用length-next的值 以避免读入越界
        int n = Math.min(length - next, len);
        使用String类的getChars方法,将指定str从next到next+n位置的数据
        复制到传入的字符数组cbuf中,起始位置从off开始 
        str.getChars(next, next + n, cbuf, off);
        移动索引游标
        next += n;
        return n;
    }
}

跳过方法 指定跳过long ns个字符内容

public long skip(long ns) throws IOException {
    synchronized (lock) {
        ensureOpen();
        如果游标已经到尾部 则说明流已经读完 不能再跳过了
        if (next >= length)
            return 0;
        n为真正的跳过的字符大小 一般是ns的大小 但如果ns
        超过了数据的总长度,那么就要使用length-next的值 以避免越界
        long n = Math.min(length - next, ns);
        这里是处理ns为负数的情况 如果ns为负数 则n一定为ns
        Math.max(-next, n)计算保证了如果ns为负数且其绝对值大于next时
        倒回next大小,回到流起点 避免越界
        即只有当读取位置大于回退的数值大小时才可以回腿,所以最多之能回退到数据的起点位置
        n = Math.max(-next, n);
        next += n;
        return n;
    }
}

标记与重置

标记方法 在指定位置做标记,与reset方法连用,可以让流回退到标记位置 
public void mark(int readAheadLimit) throws IOException {
    if (readAheadLimit < 0){
        throw new IllegalArgumentException("Read-ahead limit < 0");
    }
    synchronized (lock) {
        ensureOpen();
        mark = next;
    }
}
重置方法 移动索引游标到标记位置 
public void reset() throws IOException {
    synchronized (lock) {
        ensureOpen();
        next = mark;
    }
}

关闭方法 可以看到 StringReader是内存流 不存在数据源 所以关闭就是置为空值

public void close() {
    synchronized (lock) {
        str = null;
    }
}

示例

读入

    String str = "使用StringReader";

    StringReader  reader = new StringReader(str);

    int i=0;
    reader.mark(0);
    while((i=reader.read())!=-1)
    {
        System.out.print((char)i);
    }

    reader.reset();

    System.out.println();
    reader.skip(2);

    while((i=reader.read())!=-1)
    {
        System.out.print((char)i);
    }

输出结果

使用StringReader
StringReader

读入到字符数组

    String str = "使用StringReader";

    StringReader  reader = new StringReader(str);

    char[] chars = new char[1024];
    int len = 0;
    while ( (len = reader.read(chars)) != -1 ) {

    }
    System.out.println( new String(chars, 0, chars.length-1) );

输出结果

使用StringReader

StringWriter

概述

StringReader 字符输入流 和CharArrayReader类似 都是节点流 内存流
和CharArrayReader不同的地方是直接读入字符串而不是字符数组

用法也是类似的 都是用于接口适配 如果你需要调用的接口采用了Reader为参数
而你的数据源来自内存而不是其他外部数据源 ,那么就可以使用StringReader

源码分析

成员变量

和CharArrayReader相似

字符串内容体
private String str;
流内容长度
private int length;
索引游标 下一个流读入位置 
private int next = 0;
在流中被标记的位置
private int mark = 0;

成员方法

构造方法 很简单 传入一个String参数s 初始化成员变量即可

public StringReader(String s) {
    this.str = s;
    this.length = s.length();
}

读取字符方法 如果下一个读入位置已经超过了流内容长度 则返回-1表示已读取完毕
否则返回对应索引位置的字符对应的整型数值 并移动索引游标

public int read() throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (next >= length)
            return -1;
        return str.charAt(next++);
    }
}

读入字符 并写入到字符数组方法
入参为指定的要存储的内容的字符数组char cbuf[],数组存储起始的位置int off和终止位置int len

public int read(char cbuf[], int off, int len) throws IOException {
    synchronized (lock) {
        例行的安全检查 判断流是否开启 读入长度 起始终止位置是否越界
        ensureOpen();
        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
            ((off + len) > cbuf.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        如果索引游标超过数组长度 读取完毕 返回-1
        if (next >= length)
            return -1;
        整形值int n,设置为length-next和len之间的较小值,因为一般情况下使用len即可,
        如果len长度超过了数据的总长度,那么就要使用length-next的值 以避免读入越界
        int n = Math.min(length - next, len);
        使用String类的getChars方法,将指定str从next到next+n位置的数据
        复制到传入的字符数组cbuf中,起始位置从off开始 
        str.getChars(next, next + n, cbuf, off);
        移动索引游标
        next += n;
        return n;
    }
}

跳过方法 指定跳过long ns个字符内容

public long skip(long ns) throws IOException {
    synchronized (lock) {
        ensureOpen();
        如果游标已经到尾部 则说明流已经读完 不能再跳过了
        if (next >= length)
            return 0;
        n为真正的跳过的字符大小 一般是ns的大小 但如果ns
        超过了数据的总长度,那么就要使用length-next的值 以避免越界
        long n = Math.min(length - next, ns);
        这里是处理ns为负数的情况 如果ns为负数 则n一定为ns
        Math.max(-next, n)计算保证了如果ns为负数且其绝对值大于next时
        倒回next大小,回到流起点 避免越界
        即只有当读取位置大于回退的数值大小时才可以回腿,所以最多之能回退到数据的起点位置
        n = Math.max(-next, n);
        next += n;
        return n;
    }
}

标记与重置

标记方法 在指定位置做标记,与reset方法连用,可以让流回退到标记位置 
public void mark(int readAheadLimit) throws IOException {
    if (readAheadLimit < 0){
        throw new IllegalArgumentException("Read-ahead limit < 0");
    }
    synchronized (lock) {
        ensureOpen();
        mark = next;
    }
}
重置方法 移动索引游标到标记位置 
public void reset() throws IOException {
    synchronized (lock) {
        ensureOpen();
        next = mark;
    }
}

关闭方法 可以看到 StringReader是内存流 不存在数据源 所以关闭就是置为空值

public void close() {
    synchronized (lock) {
        str = null;
    }
}

示例

读入

    String str = "使用StringReader";

    StringReader  reader = new StringReader(str);

    int i=0;
    reader.mark(0);
    while((i=reader.read())!=-1)
    {
        System.out.print((char)i);
    }

    reader.reset();

    System.out.println();
    reader.skip(2);

    while((i=reader.read())!=-1)
    {
        System.out.print((char)i);
    }

输出结果

使用StringReader
StringReader

读入到字符数组

    String str = "使用StringReader";

    StringReader  reader = new StringReader(str);

    char[] chars = new char[1024];
    int len = 0;
    while ( (len = reader.read(chars)) != -1 ) {

    }
    System.out.println( new String(chars, 0, chars.length-1) );

输出结果

使用StringReader

StringWriter

概述

StringWriter字符输入流 和CharArrayWriter类似 都是节点流 内存流
和CharArrayWriter不同的地方是直接写入字符串而不是字符数组

用法也是类似的 都是用于接口适配 如果你需要调用的接口采用了Reader为参数
而你的数据源来自内存而不是其他外部数据源 ,那么就可以使用StringWriter

源码分析

成员变量

仅有一个StringBuffer,因为流的操作有数据改变的方法,所以简单的String类型并不能满足

  private StringBuffer buf;

成员方法

无参构造

public StringWriter() {
    buf = new StringBuffer();
    lock = buf;
}

带整型参数的构造函数,参数值值设定了内置buf初始化时的容量大小
并设置了StringBuffer对象为writer的锁对象

public StringWriter(int initialSize) {
    if (initialSize < 0) {
        throw new IllegalArgumentException("Negative buffer size");
    }
    buf = new StringBuffer(initialSize);
    lock = buf;
}

写方法

写入一个字符
public void write(int c) {
        buf.append((char) c);
    }

写入字符数组char cbuf[] 起始位置off,写入长度len
public void write(char cbuf[], int off, int len) {
    if ((off < 0) || (off > cbuf.length) || (len < 0) ||
        ((off + len) > cbuf.length) || ((off + len) < 0)) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return;
    }
    buf.append(cbuf, off, len);
}

写入字符串 此类最常用方法
public void write(String str) {
        buf.append(str);
    }

写入字符串 可设定起始位置和写入长度
public void write(String str, int off, int len)  {
    buf.append(str, off, off + len);
}

写入字符序列 和写入字符串方法类似 只不过入参是字符序列 
所以可以写入所有字符序列的实现类 如StringBuffer StringBuilder等
public StringWriter append(CharSequence csq) {
    write(String.valueOf(csq));
    return this;
}

追加写入方法 和写入大同小异 只不过返回类对象 可以链式调用

   public StringWriter append(CharSequence csq) {
        write(String.valueOf(csq));
        return this;
    }

 public StringWriter append(CharSequence csq, int start, int end) {
        if (csq == null) csq = "null";
        return append(csq.subSequence(start, end));
    }

   public StringWriter append(char c) {
        write(c);
        return this;
    }

获取字符串

 public String toString() {
        return buf.toString();
    }

获取字符缓冲

public StringBuffer getBuffer() {
        return buf;
    }

刷新和关闭 都是空实现 因为此流为内存流 无数据汇

 public void flush() {
    }

public void close() throws IOException {
}

示例

    StringBuffer sb = new StringBuffer("使用StringWriter");

    StringWriter stringWriter=new StringWriter(100);

    stringWriter.append(sb);

    System.out.println(stringWriter.toString());

    stringWriter.write("追加写入");

    System.out.println(stringWriter.toString());

输出结果

使用StringWriter
使用StringWriter追加写入

猜你喜欢

转载自blog.csdn.net/u011863951/article/details/80045239