6、 自定义字符输入流的包装类,通过这个包装类对底层字符输入流进行包装,
让程序通过这个包装类读取某个文本文件(例如,一个java源文件)时,
能够在读取的每行前面都加上有行号和冒号。
思路:
1.首先是字符的,输入的包装类,底层自然是一个一个读取字符.那么该
包装类中必然要有read()方法.
2.对于read()的数据如何让其具备一行一行的数据记录呢?必须要有一个
变量,这个变量如何去定义,怎么样这个变量才会变化呢?
3.每次一行的读取数据,那么可以在包装类中定义一个StringBuilder用来
接受数据,当读到行末尾的时候,就返回这个StringBuilder的字符串.
总结:
1.java中读取的一行一行数据,也是依靠底层一个一个读取,然后根据\n来判断读取到行末尾,再一次性返回.
2.对于判断结束标记,我们在自定义返回数据的时候,就需要给定一个可以让其结
束的标记(null 或者 -1 等等).
3.对于StringBuilder,其中接受的数据,并没用换行操作(因为底层中,一次一个字节读取,对于\r\n只是一个判断依据,并没有存储起来),因此我们需要手动,对于行结尾要添加"\r\n"以便输出时候识别换行.
思考:
java中,一次读取一行是提高了效率的操作.但是,一次读取一行其底层也是一个一个读取的操作.那么,怎么样能够证明,貌似一样的操作手法一次一行就效率更高呢?
查阅api发现,如果没有定义缓冲区,每次读取后,都要将数据从字节转换成字符数据而后返回,这样会效率极低.
个人认为:
不管是字节流还是字符流,底层都是在读取字节.只是字符流加入了一个可以让我们识别的一个编码表.如果一次读一个字符,先存储起来,等到读到行末尾再一次输出.
那么效率应该是提高在"数据返回"这个关键点上.而在底层读取啊,还有转换呀,
这些方面是没有提高效率的.
* */
public class Demo06 {
public static void main(String[] args) throws IOException {
File fi = new File("c:\\stu.txt");
String s = LineFile(fi);
System.out.println(s);
}
public static String LineFile(File fi) throws IOException {
MyLineReader mr = new MyLineReader(new FileReader(fi));
String s = null;
StringBuilder sb = new StringBuilder(); //为了让程序拥有自主控制输出,因此创建.
mr.setLen(0); //设置开始行号.
while((s = mr.MyreadLine())!= null)
{
sb.append( mr.getLen() + ":" + s + "\r\n");
}
return sb.toString(); //将数据返回,让客户拥有输出权利.
}
}
class MyLineReader
{
private int len; //自定义行数变量
private Reader fi; //读取数据流.
public MyLineReader(Reader fi)
{
this.fi = fi;
}
public String MyreadLine() throws IOException
{
len ++; //读取一行之后,len自增.
StringBuilder sb = new StringBuilder(); //将数据存储起来.
int i = 0;
while((i = fi.read())!= -1)
{
if(i == '\r')
continue;
if(i == '\n') //当独到行标记时候,将数据全部返回.
return sb.toString();
sb.append((char)i); //没有到达行标记就继续读取.
}
if(sb.length() != 0) //StringBuilder的长度不为0,就继续返回数据.
return sb.toString();
return null; //否则返回空.因为调用方法时候,是依靠返回是不是null来判断,是不是应该结束.
}
public int getLen() { //get,set方法,用来获取行号和设置行号.
return len;
}
public void setLen(int len) {
this.len = len;
}
}
|
|