黑马程序员技术交流社区
标题: readLine()问题 [打印本页]
作者: 马甲大王 时间: 2013-3-13 22:32
标题: readLine()问题
本帖最后由 张栓紧 于 2013-3-14 09:57 编辑
- import java.io.BufferedReader;
- import java.io.FileInputStream;
- import java.io.InputStreamReader;
- public class ReflectDemo2 {
- public static void main(String[] args) throws Exception {
- BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\1.txt")));
-
- String str = null;
- while((str=br.readLine())!=null){
- System.out.println(str);
- }
- }
- }
复制代码 1.txt的内容是
lisi
zhangsan
wangwu
maliu
zhaoqi
我想问的是zhaoqi后没有回车符,怎么str=br.readLine()能读到,而且打印出来了?
作者: 李易烜 时间: 2013-3-13 22:54
它不为空,肯定可以打印出来
作者: 马甲大王 时间: 2013-3-13 23:02
李易烜 发表于 2013-3-13 22:54
它不为空,肯定可以打印出来
readLine()读取到回车符才会有数据啊。
作者: 谢洋 时间: 2013-3-13 23:58
readLine() 的内部代码类似下面代码:
//定义一个缓冲区
tringBuilder sb = new StringBuilder();
int ch = 0;
//文件结尾返回-1
while((ch=r.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
//如果读到换行符,则把缓冲区的内容转为字符串返回
return sb.toString();
else
//往缓冲区添加字符
sb.append((char)ch);
}
//如果最后一行没有回车符也表读到未尾了,就把这些字符串返回去。
if(sb.length()!=0)
return sb.toString();
return null;
作者: 小路飞 时间: 2013-3-14 01:01
谢洋 发表于 2013-3-13 23:58
readLine() 的内部代码类似下面代码:
//定义一个缓冲区tringBuilder sb = new StringBuilder(); ...
从本质找问题所在,又学到了一招,谢了!
作者: 潘廖明 时间: 2013-3-14 01:03
补充下楼上的这段代码说明:
readLine()的内部算法是这样的:readLine( )虽然是一次读一行,但是归根结底他还是封装了read( )方法,进行一次一个字符的读取。
关键点:(1)判断一行结束的条件:通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。最后一行的比较特殊列外。
我们要讨论的也就是最后一行的问题:
※假设我们就只有一行字符,while执行结束后ch的值是不可能为0与-1,所以sb字符缓冲里面肯定有值。接着进行如下的判断
if(sb.length()!=0)
return sb.toString();
return null;
我们返回的值是sb.toString
假设文档是空的,就返回一个null
作者: 明锦添 时间: 2013-3-14 01:56
本帖最后由 明锦添 于 2013-3-14 02:00 编辑
private static int defaultCharBufferSize = 8192;//默认缓冲区大小
/**
* Creates a buffering character-input stream that uses an input buffer of
* the specified size.
*
* //使用指定的字符数创建一个缓冲字节输入流
*
* @param in A Reader
* @param sz Input-buffer size
*
* @exception IllegalArgumentException If sz is <= 0
*/
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
/**
* Reads a line of text. A line is considered to be terminated by any one
* of a line feed ('\n'), a carriage return ('\r'), or a carriage return
* followed immediately by a linefeed.
*
*//读取一个文本行。一条线是由任何一个终止一个换行符('\n'),回车('\r'),或一个回车紧接着一个换行。
*
* @param ignoreLF If true, the next '\n' will be skipped
*
* @return A String containing the contents of the line, not including
* any line-termination characters, or null if the end of the
* stream has been reached
*
*//一个字符串包含的内容,不包括任何线终止字符,或NULL,如果为null表示流已经读取末尾了。
*
* @see java.io.LineNumberReader#readLine()
*
* @exception IOException If an I/O error occurs
*/
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;
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);
}
}
}
//仔细研究了一下io包中的BufferedReader 的readLine() 的源码,如上,因数代码太多还有一部分我没有贴出来,
我结合这些代码看了一下,发现ReadLine()的实现,实际上只是将文件以字符数组的形式读到字符缓冲区中,然后根据'\r','\n'来拆分字符数组,返回整行(返回的行里面不包含任何行结束标识)。 楼主的情况是这样的:你的文件字符比较小 ,所以将会被一次性被读取到字符缓冲数组中,
你的文件在字符缓冲数组中应该显示为:l i s i z h a n g s a n \r \n w a n g w u \r \n m a l i u \r \n z h a o q i 一共37个字符:29字符+4对'\r' '\n',(为了便于看,我在每个字符间加了一个空格)然后,实现从这个数组中从前往后遍历(代码中实现的是对有效字符的遍历,即从下标[0]~[36]之间的字符的遍历),在本例中,会在四个'\r'的地方截断字符,并返回一条字符串(以StringBuffer连接单个字符,最后以toString()的形式返回字符串),当遇到指定需要忽略或是已经跳过一个字符而且本次字符是'\n'时,再次跳过本字符 。
如此往复,当字符遍历到最后一个有效字符时终止,并把拼接好的字符串返回,由些可见楼主的最后一行能正常读出来,跟最后一行是否有回车/换行符没有任何关系的,只是因为它的有效字符读完了就结束(断行结束)了。
若文件比较大,它会先读文件填满缓冲区,遍历(取整行返回)缓冲区到最后一个字符时,再次去从文件中读取字符填满缓冲区,再遍历(取整行返回)... 直到文件读完为止。
作者: 马甲大王 时间: 2013-3-14 09:57
谢洋 发表于 2013-3-13 23:58
readLine() 的内部代码类似下面代码:
//定义一个缓冲区tringBuilder sb = new StringBuilder(); ...
谢谢啦!呵呵
作者: 谢洋 时间: 2013-3-14 10:12
张栓紧 发表于 2013-3-14 09:57
谢谢啦!呵呵
不用客气,哥是从笔记那里翻出来的
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |