Java readLine 源码分析


readLine

  • BufferedReader 类继承自 Reader,又新增了按行读取的方法:String readLine(),该方法返回改行不包含结束符的字符串内容,如果已到达流末尾,则返回 null
  • 使用范例如下:
public class Test {
    public static void main(String[] args) throws IOException {
        // 创建流对象
        BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\80626\\Desktop\\1.txt"));
        // 定义字符串,保存读取的一行文字
        String line = null;
        // 循环读取,读取到最后返回null
        while ((line = br.readLine()) != null) {
            System.out.print(line);
            System.out.println("------");
        }
        // 释放资源
        br.close();
    }
}

1. API 中的方法

    public String readLine() throws IOException {
        return readLine(false);
    }
  • 其实调用了 String readLine(boolean ignoreLF) 方法,ignoreLF = true 时忽略下一个换行符 '\n'
	/** If the next character is a line feed, skip it */
    private boolean skipLF = false;
  • BufferedReader 类的私有变量 skipLF = false
  • 阅读说明可知,readLine() 方法的主要功能是读取一行文本,换行符 '\n',回车符 '\r',换行符后的回车符,或到达文件结尾都被认为是终止的。它会返回一个包含该行内容的字符串,不包括任何行终止字符,如果到达流的末尾而没有读取任何字符,则为 nullreadLine() 的方法如下:
	String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        return s.toString();
                    else
                        return null;
                }
                boolean eol = false;
                char c = 0;
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\n'))
                    nextChar++;
                skipLF = false;
                omitLF = false;

            charLoop:
                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);
            }
        }
    }
  • 阅读 BufferedReader 类,有一个私有的类变量 defaultCharBufferSize
	private static int defaultCharBufferSize = 8192;
  • 可见,readLine() 调用了一个死循环,会不断往 Buffer 里添加数据,如果不指定 Buffer 大小,则 readLine() 使用的 Buffer 有 8192 个字符(8*1024),在达到 Buffer 大小之前,只有遇到 /r/n/r/n 才会返回;
  • 使用 socket 之类的数据流时,要避免使用 readLine(),以免为了等待一个换行或回车符而一直阻塞;

2. 网络模式注意事项

  • 在网络上,readLine() 是阻塞模式,也就是说如果 readLine() 读取不到数据的话,会一直阻塞,而不是返回 null,所以如果你想要在 while 循环后执形相关操作是不可能的,因为里面是一个死循环,一旦读不到数据,它又开始阻塞,因此永远也无法执形 while 循环外面的操作,所以应该把操作放在 while 循环里面;
  • 在 while 循环里面判断 readLine()!= null 的时候要赋值给一个 String,因为如果不为 null,那么这时候已经读了一行。如果用 while (br.readLine()!=null),那么下面没法再获取到这一行,所以应该用 while ((line = br.readLine())!=null){}
  • readLine() 通过下列字符之一即可认为某行已终止:换行 '\n'、回车 '\r' 或回车后直接跟着换行,所以我们在发送数据的时候要再后面加上这些标志符,否则程序会阻塞。而直接用下面这种方法:PrintStream ps = new PrintStream(socket.getOutputStream(), true, "UTF-8");ps.println();ps.println() 已经包含换行了,所以不要用 print(),若是要就要在后面加上换行符;
  • readLine() 只有在数据流发生异常或者另一端被 close() 掉时,才会返回 null 值。

推荐阅读:Java buffered stream 缓冲流 >>>

发布了281 篇原创文章 · 获赞 285 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Regino/article/details/105060868