String作为数据源
1.StringReader 是读, 从一个String中读取,所以需要一个String ,通过构造方法传递
2.StringWriter是写, 写入到一个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();
}
可以看出StringReader只有一个版本的构造方法,接受一个String作为参数
String str指向这个字符串
length 为字符串长度
next为读取元素的下标索引
mark为标记点
2.函数
1.提供了两个版本的read
public int read() throws IOException //读取一个字符
public int read(char cbuf[], int off, int len) throws IOException
//读取len个数的字符到指定的字符数组cbuf[],保存到指定位置off
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (next >= length)
return -1;
return str.charAt(next++);//调用String类下面的函数
}
}
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);//调用String类下面的函数
next += n;
return n;
}
2.ready方法
用来判断数据源是否存在
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return true;
}
}
private void ensureOpen() throws IOException {
if (str == null)
throw new IOException(“Stream closed”);
}
3.标记相关的方法
A.判断是否支持标记操作,返回true,说明始终支持
public boolean markSupported() {
return true;
}
B.标记操作:这里仅仅是一个标识,在读取的时候read还是根据next进行读取的,该操作对read操作读取位置无影响
public void mark(int readAheadLimit) throws IOException {
if (readAheadLimit < 0){
throw new IllegalArgumentException(“Read-ahead limit < 0”);
}
synchronized (lock) {
ensureOpen();
mark = next;
}
}
C.重置操作:将next置为标记的mark值,mark函数要与reset函数连用才能达到从指定位置读取的目的
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
next = mark;
}
}
4.skip函数
跳过流中指定数量的字符 返回跳过的字符数
如果读取或跳读了整个字符串,则此方法无效且始终返回 0
此处 ns 参数可能为负数,ns 为负值导致此流向后跳读
负返回值指示向后跳读 向后跳读不可能倒过字符串的开头
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;
}
}
StringWriter:(他的所有实现都是StringBuffer)
1.属性和构造方法
//底部实际上都是调用的stringBuffer
private StringBuffer buf;//buf存放写入的字符串
public StringWriter() {
buf = new StringBuffer();//默认大小16
lock = buf;
}
public StringWriter(int initialSize) {
if (initialSize < 0) {
throw new IllegalArgumentException(“Negative buffer size”);
}
buf = new StringBuffer(initialSize);
lock = buf;
}
2.几种写操作
四个write操作,三个append方法
四个write操作全部调用了StringBuffer的append操作
三个append操作调用本函数中的那四个Write操作
public void write(int c) {
buf.append((char) c);
}
//单个字符
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.substring(off, off + len));
}
//写入字符串的一部分
public StringWriter append(CharSequence csq) {
if (csq == null)
write(“null”);
else
write(csq.toString());
return this;
}
//写入字符串
public StringWriter append(CharSequence csq, int start, int end) {
CharSequence cs = (csq == null ? “null” : csq);
write(cs.subSequence(start, end).toString());
return this;
}
//写入部分字符串
public StringWriter append(char c) {
write©;
return this;
}
//写入单个字符
3.其他方法
//返回字符串
public String toString() {
return buf.toString();//底层调用的是StringBuffer
}
//获取写入的内容
public StringBuffer getBuffer() {
return buf;
}
//测试代码
package java中期.IO;
import java.io.*;
//访问字符串:输入输出流
//StringReader,StringWriter
public class stringReaderWriterTest {
public static void StringReader(){
String str="想吃汉堡奶茶烤肉和火锅嗝到了冬天就是吃再多也吃不饱啊让我死会儿";
try {
//传入一个自定义好的字符串,构造方法只有这一种
StringReader stringReader = new StringReader(str);
//public boolean ready() throws IOException
//可能会抛出IO异常,判断字符串是否传进去了,即数据源是否存在
System.out.println("数据源是否存在:"+stringReader.ready());
// public boolean markSupported() {return true;}
// 返回true,说明始终支持标记操作
// 在我们前面学过的FileInputStream和FileReader这两个类里面也提供了这样的方法,不过默认返回为false
System.out.println("是否支持标记操做:"+stringReader.markSupported());//是否支持标记操作
char[] chars=new char[3];
int read = stringReader.read(chars,0,3);
System.out.println("读取前三个个字符:"+new String(chars,0,3));
// public void mark(int readAheadLimit) throws IOException {
// if (readAheadLimit < 0){throw new IllegalArgumentException("Read-ahead limit < 0");可能会抛出Io异常
//readAheadLimit - 在仍保留该标记的情况下,对可读取字符数量的限制。
// 由于该流的输入来自一个字符串,不存在实际的限制,因此,此参数决不能为负数,否则将被忽略。
//标记操作,用该方法时要先用markSupported()函数,即使用标记操作前一定要先判断是否支持
stringReader.mark(2);
char[] chars1=new char[3];
int read2 = stringReader.read(chars1,0,3);
System.out.println("再读取三个个字符:"+new String(chars1,0,3));
// 重置指针void reset() throws IOException 可能会抛出IO异常
//将该流重置为最新的标记,如果从未标记过,则将其重置到该字符串的开头
stringReader.reset();
char[] chars2=new char[3];
int read3 = stringReader.read(chars2,0,3);
System.out.println("reset操作后读取三个字符:"+new String(chars2,0,3));
//TODO: mark使用并不相当于指针(跟RandomAccessFile的seek操作不是一个性质)
// TODO:在调用read的时候,read函数的读取仍然是根据next值读取的。mark只是一个标记作用,没有改变next值
// TODO:只有和reset一起使用,reset函数把mark标记赋值给next,这个时候mark就像书签一样,读取的时候才从上次标记的位置开始读取
//跳过流中指定数量的字符 返回跳过的字符数
System.out.println("跳过的字符数为:"+stringReader.skip(-5));
//负数代表往前跳,但不会超出范围
int read1 = stringReader.read();
System.out.println("进行跳转后读取一个字符:"+(char) read1);
//关闭操作,仅仅把字符串置为null
stringReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void StringWriter(){
StringWriter stringWriter = new StringWriter();
//写入数据
stringWriter.write('今');
stringWriter.append("天是个好天气");
//public StringBuffer getBuffer() {return buf;}
//得到写入的字符串
StringBuffer stringWriterBuffer = stringWriter.getBuffer();
//public String toString() {return buf.toString();}
//得到写入的字符串
System.out.println(stringWriter.toString());
//不涉及缓存,刷新无实际意义,里面为空语句
stringWriter.flush();
try {
//关闭操纵,空语句,无实际含义,不涉及缓存
stringWriter.close();
//因此,关闭后照常可以使用,例如
stringWriter.append("出去玩吧");
System.out.println(stringWriter.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
StringReader();
// StringWriter();
}
}