IO流分类图
访问字符串
StringReader是字符输入流,Reader的子类,从一个String中读取,所以需要一个String ,通过构造方法传递
StringWriter是字符输出流,Writer的子类,写入到一个String中去,所以它内部提供了一个StringBuffer中用来保存数据
StringReader
1. 属性和构造方法
private String str; private int length; private int next = 0; private int mark = 0; public StringReader(String s) { //传入字符串 this.str = s; this.length = s.length(); } str :指向这个字符串 length :为字符串长度 next :为读取元素的下标索引 mark :为标记点
2. 基本方法
1. read()方法
//读取一个字符 public int read() throws IOException { synchronized (lock) { ensureOpen(); if (next >= length) return -1; return str.charAt(next++); } }
注::从中可看出StringReader 将String字符串操作 适配成 Reader字符操作 对外提供服务 —> StringReader是一个适配器类
//批量读取 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; } if (next >= length) return -1; int n = Math.min(length - next, len); str.getChars(next, next + n, cbuf, off); next += n; return n; } }
2. 标记相关方法
//判断是否支持标记 public boolean markSupported() { return true; }
注: FileInputStream 和 FileReader 都不支持标记
//标记 public void mark(int readAheadLimit) throws IOException { if (readAheadLimit < 0){ throw new IllegalArgumentException("Read-ahead limit < 0"); } synchronized (lock) { ensureOpen(); mark = next; } }
注: mark的使用并不相当于指针,需要和reset()方法一起使用 --> 和RandomAccessFile的seek操作不是一个性质
//重置指针 public void reset() throws IOException { synchronized (lock) { ensureOpen(); next = mark; } }
注: 将mark标记赋给next,reset()和mark()两个方法配合使用
//跳过流中指定数量的字符 返回跳过的字符数 public long skip(long ns) throws IOException { synchronized (lock) { ensureOpen(); if (next >= length) return 0; // Bound skip by beginning and end of the source long n = Math.min(length - next, ns); n = Math.max(-next, n); next += n; return n; } }
注: 正数往前跳,负数往后跳
3. 测试代码
//访问字符串 StringReader import java.io.IOException; import java.io.StringReader; public class StringReader_work { public static void StringReader() { String str = "今天外面真的冷啊果然应该点外的"; try { //1. 构造方法 传入字符串 StringReader stringReader = new StringReader(str); //2. int read() 读操作,读取一个字符 (将String字符串操作 适配成 Reader字符操作 对外提供服务) // int read=stringReader.read(); // System.out.println((char) read); //int read(char cbuf[]) throws IOException 批量读 char[] chars = new char[3]; int read1=stringReader.read(chars); System.out.println(new String(chars,0,3)); //int read(char cbuf[], int off, int len) 批量读 // char[] chars1 = new char[3]; // int read2=stringReader.read(chars1,0,3); // System.out.println(new String(chars1,0,3)); // boolean ready() 判断数据源是否存在 stringReader.ready(); //3. markSupported() 是否支持标记 FileInputStream和FileReader 都不支持 System.out.println("是否支持标记:"+stringReader.markSupported()); // void mark(int readAheadLimit) throws IOException 标记 //TODO: 测试发现并未从标记位置读,依旧是接着原先next所指位置读数据 stringReader.mark(5); char[] chars2=new char[3]; int read3 = stringReader.read(chars2,0,3); System.out.println("mark标记后读三个数:"+new String(chars2,0,3)); //TODO:mark使用并不相当于指针 --> 和RandomAccessFile的seek操作不是一个性质 // void reset() throws IOException 重置指针 // 单独使用 reset() 方法 stringReader.reset(); char[] chars3=new char[3]; int read4 = stringReader.read(chars3,0,3); System.out.println("单独使用reset()方法:"+new String(chars3,0,3)); // mark()方法 与 reset()方法 结合使用 stringReader.mark(2); stringReader.reset(); char[] chars4=new char[3]; int read5 = stringReader.read(chars4,0,3); System.out.println("mark()与reset()结合使用:"+new String(chars4,0,3)); // long skip(long ns) throws IOException 跳过流中指定数量的字符 返回跳过的字符数 stringReader.skip(2); //正数往前跳 // stringReader.skip(-2); //负数往后跳 char[] chars5=new char[3]; int read6 = stringReader.read(chars5,0,3); System.out.println("向前跳两个字符:"+new String(chars5,0,3)); //关闭流 stringReader.close(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { StringReader(); } }
运行结果
读取前三个字符:今天外 是否支持标记:true mark标记后读三个数:面真的 单独使用reset()方法:面真的 mark()与reset()结合使用:冷啊果 向前跳两个字符:该点外