- 浏览: 304922 次
- 性别:
- 来自: 山西
博客专栏
-
天天编程
浏览量:22014
最新评论
-
变脸小伙:
运用到了场景中,希望接力
StringBuffer源码理解 -
fangsj:
IE9 安全设置 把这个禁用掉了
spring mvc 文件上传+本地预览+一次提交 -
xu-ch:
今天面试,遇到这题,求出了相似度,面试官问我算法原理是什么,悲 ...
计算字符串相似度算法——Levenshtein -
flywangfei:
你是创新工场的么?
计算字符串相似度算法——Levenshtein -
scwuwei:
六点起床比较好
《4点起床-最养生和高效的时间管理》读书笔记
1.BufferedReader
1.1 继承关系
public class BufferedReader extends Reader { //这个又是装饰模式 private Reader in; }
1.2 构造方法
public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } //默认缓存数组的大小 private static int defaultCharBufferSize = 8192; //构造方法 public BufferedReader(Reader in, int sz) { //这个方法可参考前面的Writer源码,只要是将锁赋值 super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); //装饰模式。。 this.in = in; cb = new char[sz]; nextChar = nChars = 0; } //两个上面用到的参数,用于缓存数据,是字符(char)数组,不是字节(byte)数组。 private char cb[]; private int nChars, nextChar;
1.3 标记有关
在看read方法之前先看一眼 标记mark有关的方法有点帮助。为看懂read做铺垫
//标记流中的当前位置,带入的参数表示标记所占的空间 public void mark(int readAheadLimit) throws IOException { if (readAheadLimit < 0) { throw new IllegalArgumentException("Read-ahead limit < 0"); } synchronized (lock) { ensureOpen(); this.readAheadLimit = readAheadLimit; markedChar = nextChar; markedSkipLF = skipLF; } } //回到标记位置 public void reset() throws IOException { synchronized (lock) { ensureOpen(); if (markedChar < 0) throw new IOException((markedChar == INVALIDATED) ? "Mark invalid" : "Stream not marked"); //下面两个参数在读方法中会有详细解释 nextChar = markedChar; skipLF = markedSkipLF; } }
1.4 read
这个方法中fill()是重点,有点绕,但看懂后就觉得很清晰,能完全理解bufferedReader的原理。
看完这个方法再回去看3.3的标记部分,就很容易看懂。
public int read() throws IOException { //锁,看来读得时候也只能一个方法读。 synchronized (lock) { //确保输入流不是空。 ensureOpen(); //这个循环和while一样。 for (;;) { //下面的判断为是否下一个读取的字符超出了缓存数组中实际包含数据的大小。 if (nextChar >= nChars) { //下一个字符超出或者等于缓存数组的大小 //这个是核心的方法,里面有标记的内容,详细的看下面内容。 fill(); //如果还是超出,则表示输入流读完了。 if (nextChar >= nChars) return -1; } //如果下一个字符是换行符.这个变量只有在readLine里面才变为true。和\n\r有关,可忽略。针对不同的平台的 if (skipLF) { skipLF = false; if (cb[nextChar] == '\n') { nextChar++; continue; } } //返回当前读的字符,并将要读字符+1 return cb[nextChar++]; } } } //下面的变量是用于fill方法里的 //下面两个变量是标记的状态, -1为未启动标记,-2为标记失效。 private static final int INVALIDATED = -2; private static final int UNMARKED = -1; //标记的位置 private int markedChar = UNMARKED; //nChars表示现在缓存数组中已经存在多少个字符。 //nextChar表示下一个读取的位置,从0开始,这个只是缓存数组中的位置,并不是读取流的位置。 private int nChars, nextChar; //标记分配的空间大小。超出后,如果缓存数组重新处置,则标记失效。 private int readAheadLimit = 0; //将字符数组读满,然后直接返回数组中的某个值。里面主要考虑的是标记的问题。 //这个和BufferedInputStream差不多,一个是byte[],这个是char[] private void fill() throws IOException { //计算这次缓存数据的起始位置,起始位置之前保存的是标记的内容。 int dst; if (markedChar <= UNMARKED) { //这里表示没有使用标记,或者标记失效。 dst = 0; } else { //表示使用标记 //这个变量表示标记之后实际使用了多少空间 int delta = nextChar - markedChar; if (delta >= readAheadLimit) { //如果超过了标记初始的空间。 //标记失效 markedChar = INVALIDATED; //标记空间赋0 readAheadLimit = 0; //缓存数据起点0 dst = 0; } else { //如果未超过标记初始的空间。 if (readAheadLimit <= cb.length) { //分配的标记空间小于缓存数组的长度 //将标记后实际使用长度复制到数组的开始。 System.arraycopy(cb, markedChar, cb, 0, delta); //将标记的位置赋0,标记所占空间仍然是原来的空间,不会缩小。 markedChar = 0; //数据缓存的起点 dst = delta; } else { //长度不够,新建一个。 char ncb[] = new char[readAheadLimit]; //和上面一样,复制标记到最前面 System.arraycopy(cb, markedChar, ncb, 0, delta); //将引用更新 cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } } //下面是读数据,读出一定长度,默认cb的长度8192,cb在BufferedReader中是唯一的缓存数组。 int n; //这个地方读的方法中不可能返回0.所以只会执行一次 do { //从标签之后读,读满cb字符数组,注意,这里是调用in的读方法。 n = in.read(cb, dst, cb.length - dst); } while (n == 0); //读到数据的情况,没有读到的话就不做任何操作。 if (n > 0) { //现在缓存空间中已有的真实缓存数量 nChars = dst + n; //下一个读取的位置。 nextChar = dst; } }
其它的read方法和这个类似。
一次读出很多字符的时候,处理的策略是:
a.缓存数组不够,就用in直接读,不经过缓存.
b.缓存数组够,就将缓存中读出。
c.缓存数组够,但读完后还没读满,则继续从in中接着读,不够的部分不过缓存数组。
1.5 readLine
这个是用的比较多的方法,所以列出来。这个方法在有上面的基础上,还是很好懂的。
String readLine(boolean ignoreLF) throws IOException { //传入的布尔值默认为false StringBuffer s = null; int startChar; synchronized (lock) { ensureOpen(); boolean omitLF = ignoreLF || skipLF; //这个是什么?goto? bufferLoop: //while for (;;) { //下一个字符超出缓存数组大小,这里nextChar是从0开始的,所以相等的时候就代表已经超出了缓存数组范围。 if (nextChar >= nChars) fill(); //下面的if是判断流的末尾,读完了就返回null,或者将之前读的内容返回 if (nextChar >= nChars) { if (s != null && s.length() > 0) return s.toString(); else return null; } //表示没有到末尾. boolean eol = false; char c = 0; int i; //这个是处理\r\n的情况,不进行两次判断,忽略 if (omitLF && (cb[nextChar] == '\n')) nextChar++; skipLF = false; omitLF = false; charLoop: //遍历缓存数组,直到\n或者\r for (i = nextChar; i < nChars; i++) { c = cb[i]; if ((c == '\n') || (c == '\r')) { //表示读取到了换行 eol = true; break charLoop; } } //记录读取开始的地方, startChar = nextChar; //要读的下一个字符。 nextChar = i; //读取到换行,而不是读完缓存。 if (eol) { String str; if (s == null) { str = new String(cb, startChar, i - startChar); } else { s.append(cb, startChar, i - startChar); str = s.toString(); } nextChar++; if (c == '\r') { skipLF = true; } return str; } //表示读完了缓存数组,还需要继续读。 if (s == null) s = new StringBuffer(defaultExpectedLineLength); s.append(cb, startChar, i - startChar); } } }
1.6 其它方法
skip 就是先把缓存数组中跳过去,如果缓存数组不够,就再将数据读入缓存数组,再跳,一直循环。
ready 表示缓存是否读完了,没什么用处。
markSupported 是否支持标记
close 流等需要关闭的东西都关闭。
2.BufferedWriter
2.1 继承关系
public class BufferedWriter extends Writer { //装饰模式 private Writer out; }
2.2 构造函数
将缓存数组初始化,并且根据平台初始化换行符号。
public BufferedWriter(Writer out, int sz) { super(out); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); this.out = out; cb = new char[sz]; nChars = sz; nextChar = 0; //获取换行的符号\n \r,和方法System.getProperty("line.separator")一样 lineSeparator = (String) java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("line.separator")); }
2.3 write有关
public void write(int c) throws IOException { synchronized (lock) { //判断是否有输出流 ensureOpen(); //如果缓存数组写满了,就flush数组。 if (nextChar >= nChars) flushBuffer(); //将内容写入缓存数组中 cb[nextChar++] = (char) c; } } //flush,这个方法就知道flush的重要性, void flushBuffer() throws IOException { synchronized (lock) { ensureOpen(); if (nextChar == 0) return; //将数据写入流 out.write(cb, 0, nextChar); nextChar = 0; } }
用的比较多的写字符串。就是将字符串转变成字符数组。
public void write(String s, int off, int len) throws IOException { synchronized (lock) { ensureOpen(); int b = off, t = off + len; while (b < t) { int d = min(nChars - nextChar, t - b); //将字符串转为字符数组 s.getChars(b, b + d, cb, nextChar); //写入缓存数组 b += d; nextChar += d; if (nextChar >= nChars) //如果写满了,就写入流中。 flushBuffer(); } } }
2.4 其它
a.writeLine 写一个换行
public void newLine() throws IOException { //同样写到缓存数组里 write(lineSeparator); }
b.flush,这个也不多说了。
public void flush() throws IOException { synchronized (lock) { flushBuffer(); out.flush(); } }
c.close 关闭所有该关闭的.
public void close() throws IOException { synchronized (lock) { if (out == null) { return; } try { //最后还释放了一次。不过没有执行flush方法,所以在close前还是要执行一次flush! flushBuffer(); } finally { out.close(); out = null; cb = null; } } }
3.结束
看完这个字符流,清晰了好多,开始看的比较慢,但是后来越来越快,水到渠成。
发表评论
-
fastcgi中的多线程使用
2012-04-06 22:38 138010.背景 在项目中加入了 ... -
crc循环校验原理和实现
2012-03-29 23:33 194421.CRC简介 CRC(cyclical redundanc ... -
TreeMap源码理解
2012-01-31 10:44 01.首先看构造方法 public TreeMap() { ... -
HashMap源码理解
2012-01-30 21:33 1897看看HashMap对应的源码。 1.类、接口关系 ... -
StringUtils源码理解(下)
2012-01-16 15:46 2264本文介绍StringUtils的剩下的两个方法 1. ... -
StringUtils源码理解(中)有点意思的方法
2012-01-12 00:17 3705这次不按照前面的介绍了,方法都大同小异,下面就介绍几个有意思一 ... -
StringUtils源码理解(上)
2012-01-11 23:08 4823StringUtils 源码,使用的是commons-lang ... -
Properties源码理解
2012-07-05 12:23 3981Properties用来读配置文件 ... -
字符流(一)Reader和Writer源码理解
2011-11-27 20:32 15211.Reader 1.1 继承关系 public ... -
DataInputStream和DataOutputStream源码理解
2011-11-17 00:02 44841.FilterInputStream简介 列出主要的内 ... -
InputStream,OutputStream源码理解
2011-11-09 22:50 34231.理解字节流和字符流 按流的形式分: 字节流和字符流。 ... -
File源码理解
2011-11-07 23:55 44131.构造函数 最基本的构 ... -
Thread源码理解
2011-10-23 14:36 43641.首先看一下Runnable接口 ... -
泛型简单回顾
2011-09-06 23:36 1348泛型的简介 1.java引入泛型的好处是安全简单。 2. ... -
LinkedList源码理解
2011-08-31 00:26 1459LinkedList源码 0.首先这个类中的两个变量 ... -
Vector源码理解
2011-08-29 23:44 1552Vector类 1.系统的变量 //记录元素的数组 pr ... -
ArrayList源码理解
2011-08-15 21:02 1769构造方法: ... -
Arrays源码理解
2011-08-15 20:34 13801.equals public static boo ... -
StringBuffer源码理解
2011-06-22 19:39 5729StringBuffer 存储和操作字符串 它所继承实现的类 ...
相关推荐
与`BufferedReader`类似,我们通常会先创建一个`FileOutputStream`,然后通过`OutputStreamWriter`将其转换为字符流,最后将`OutputStreamWriter`传递给`BufferedWriter`。 ```java FileOutputStream fos = new ...
6. **文档**:提供的Word文档很可能是对源码的详细解释,包括步骤、注意事项和可能遇到的问题,这有助于理解和学习字节流和字符流的使用。 总的来说,这个压缩包提供了一个很好的学习机会,你可以通过实际运行代码...
总的来说,理解Java的IO系统,特别是字节流和字符流的概念,对于开发高效、可靠的程序至关重要。通过选择合适的流类型、使用缓冲流和桥接流,以及利用工具类,开发者可以更好地处理各种数据输入输出需求。在实际项目...
3. **字符流**:Reader和Writer是所有字符流的基类,例如 FileReader 和 FileWriter。字符流内部使用了编码解码机制,适合处理文本数据。BufferedReader和BufferedWriter用于提高读写效率,通过缓冲区批量处理数据。...
Java的BufferedWriter和BufferedReader是Java IO流中用于提高读写效率的两个关键类。它们都通过内部缓冲区来批量处理数据,从而减少对底层流的直接操作次数,提高性能。 **BufferedWriter** BufferedWriter是一个...
过滤字符流,如InputStreamReader和OutputStreamWriter,用于在字节流和字符流之间转换。 二、字符集 字符集是表示字符的规则集合,Java使用Unicode字符集。常见的字符集有ASCII、GBK、UTF-8等。在Java中,字符流...
标签中的"源码"可能指的是查看和理解这些流类的内部实现,这对于深入学习和调试问题非常有帮助。而"工具"可能指的是利用这些流类来构建实用的I/O工具,比如文件复制、格式转换等。 在处理运行时需要加的包,确保在...
在Android系统中,IO流遵循Java的标准IO模型,分为字节流和字符流两大类。字节流处理的是8位的字节数据,包括InputStream和OutputStream两个抽象基类,分别用于输入和输出。字符流则处理16位的Unicode字符,对应的...
Reader和Writer接口是字符流的父接口,具体实现如BufferedReader和BufferedWriter,它们提供了缓冲功能,提高了读写效率。 3. 转换流:InputStreamReader和OutputStreamWriter是字节流到字符流的桥梁,可以指定字符...
在Java编程语言中,字节流、字符流、对象流和序列化是处理数据传输和存储的核心概念。这些概念在程序设计中起着至关重要的作用,尤其是在进行输入输出操作时。下面将对这些主题进行详细解释。 1. 字节流(Byte ...
对于字符流,BufferedReader和BufferedWriter提供了类似的功能。 文件复制是一个常见的I/O操作,可以使用FileInputStream和FileOutputStream结合DataInputStream和DataOutputStream实现,或者使用NIO(New IO)框架...
7. **源码分析**:提供的源码可以作为学习和理解字符编码转换机制的一个实例。通过阅读源码,我们可以深入理解Java如何处理编码转换,以及如何设计和实现这样一个工具。 这个工具可能包含了一个命令行界面或者图形...
- InputStreamReader和OutputStreamWriter:作为字节流和字符流之间的桥梁,它们分别将字节流转换为字符流和反之。 3. 滤流器流(Filter Stream): - FilterInputStream和FilterOutputStream:提供了对字节流...
例如,通过网络接收数据时,可能需要先使用Socket建立连接,然后通过InputStream读取字节,再通过InputStreamReader和BufferedReader转化为字符流进行处理。 在标签中提到的“源码”部分,理解流的工作原理有时需要...
- 字符流:Reader和Writer是所有字符输入流和输出流的基类,FileReader和FileWriter用于读写文本文件。 - 缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader和BufferedWriter提供缓冲功能,提高...
转换流允许在字节流和字符流之间转换,如InputStreamReader/OutputStreamWriter,它们在字节流与字符流之间建立桥梁,使得我们可以使用特定的字符集进行编码和解码。 5. **对象流(Object Stream)** 对象流如...
Java中的转换流(`InputStreamReader`和`OutputStreamWriter`)用于在字节流和字符流之间进行转换。它们是连接字节流和字符流的桥梁,因为Java的I/O系统是基于字节的,但字符集如UTF-8、GBK等是以字符为单位的。...
通过以上内容的学习,你将能够熟练掌握Java语言的基础,并具备阅读和理解Java源码的能力。同时,随着实践经验的积累,你将逐渐深入到更高级的主题,如设计模式、框架应用、数据库连接等,成为一名合格的Java开发者。