关于java IO流中lineNumberReader类的getLineNumber()方法


有如下代码:
import java.io.*;
import java.util.*;
public class Exercise1 {
public static void main(String[] args)
{
try
{
BufferedReader in=new BufferedReader(new FileReader("data1.txt"));
String s=new String();
String s1=new String();
Vector test=new Vector();
int size=0;
while((s=in.readLine())!=null)
test.addElement(s);
//-----------------------
/*size=test.size();
for(int i=size-1;i>=0;i--)
System.out.println(test.elementAt(i));*/
//------------------------------------------------------
size=test.size();
for(int i=0;i<size;i++)
s1=s1+(String)test.elementAt(i)+"\n";
LineNumberReader li=new LineNumberReader(new StringReader(s1));
BufferedReader in1=new BufferedReader(li);
//PrintWriter out1=new PrintWriter(new BufferedWriter(new FileWriter("data3.txt")));
while((s=in1.readLine())!=null)
System.out.println("Line"+li.getLineNumber()+": "+s);
in1.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
}

data1.txt文件中有有5行,最终输出无法得到正确的行号,输出如下:
Line5: today is Monday
Line5: tomorrow is TuesDay
Line5: the day after tomorrow is wednesday
Line5: i love hdusadjsa
Line5: this is hahha!!!
但是我用li.getLineNumber()时就可以正确得到行号,此时完全不用in1。这个是我方法是我仿照Thinking in java中的例子写的。不知道哪里错了??给位能否指正。Thx

10 个解决方案

#1


li.getLineNumber()是得到总共有几行吧,那你就用 一个counter, counter++来打印吧

#2


是跟in1.readLine 有关系
while((s=in1.readLine())!=null) {
                System.out.println("Line "+li.getLineNumber()+": "+s);
            }

in1.readLine() 时,in1需要按照一行一行来输出自己的内容,但输出之前in1必须将li的内容全部读完,所以li的lineNumber就到了第5行了。

#3


引用 2 楼 magi1201 的回复:
是跟in1.readLine 有关系
while((s=in1.readLine())!=null) {
                System.out.println("Line "+li.getLineNumber()+": "+s);
            }

in1.readLine() 时,in1需要按照一行一行来输出自己的内容,但输出之前in1必须将li的内容全部读完,所以li的lineNumber就到了第5行了。

但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?

#4


引用 3 楼 envy111 的回复:
但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?

 没看过thinking in java ,不过跟前有一本,楼主仿的哪个章节的例子呢,我看看去,我这里的是第四版的。

#5


引用 4 楼 magi1201 的回复:
Quote: 引用 3 楼 envy111 的回复:

但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?

 没看过thinking in java ,不过跟前有一本,楼主仿的哪个章节的例子呢,我看看去,我这里的是第四版的。

Thinking in java  中文第四版    10.7.4 小节     NewIODemo.java这个例子   你看下?是不是我的理解有问题。

#6


引用 5 楼 envy111 的回复:
但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?


看了开头我还想问,用了那本书上的例子,太老了,完全可以扔掉了。还在用Vector

而且,现在显然楼上几位告诉你的是正确答案。getLineNumber,代表的是这个对象,当前读到第几行。你在全部读完,放入Vector之后,再去调用getLineNumber,显然他只会告诉你最后一行的行号。
一开始是0,每次调用read类方法的时候,碰到'\n',就会+1。

#7


引用 6 楼 shine333 的回复:
Quote: 引用 5 楼 envy111 的回复:

但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?


看了开头我还想问,用了那本书上的例子,太老了,完全可以扔掉了。还在用Vector

而且,现在显然楼上几位告诉你的是正确答案。getLineNumber,代表的是这个对象,当前读到第几行。你在全部读完,放入Vector之后,再去调用getLineNumber,显然他只会告诉你最后一行的行号。
一开始是0,每次调用read类方法的时候,碰到'\n',就会+1。

好吧,我是觉得经典书籍不应该犯这样的错误啊!

#8


引用 5 楼 envy111 的回复:
Thinking in java  中文第四版    10.7.4 小节     NewIODemo.java这个例子   你看下?是不是我的理解有问题。

 我看的thinking in java 第十章只到10.7.2 是嵌套类的从多层嵌套类访问外部类的成员 木有10.7.4节。6楼大牛已经确认我们的理解是对的,这个就可以先过了,哈哈。

#9


	String text = "a\r\nb\r\nc\r\n";

LineNumberReader r = new LineNumberReader(new BufferedReader(new StringReader(text)));

String tmp = null;
while ((tmp = r.readLine()) != null)
System.out.println("Line" + r.getLineNumber() + ": " + tmp);
r.close();


lz应该用LineNumberReader 来包装BufferedReader而不是反过来。

BufferedReader  的缓冲区默认是8192 lz的文本内容应该还没这么多,用BufferedReader包装LineNumberReader 的话直接就给缓冲完了,所以行号一直是5。

#10


引用 5 楼 envy111 的回复:
Quote: 引用 4 楼 magi1201 的回复:

Quote: 引用 3 楼 envy111 的回复:

但我这是按照Thinking in java这本书上的例子来写的,不可能有这么明显的错误吧?

 没看过thinking in java ,不过跟前有一本,楼主仿的哪个章节的例子呢,我看看去,我这里的是第四版的。

Thinking in java  中文第四版    10.7.4 小节     NewIODemo.java这个例子   你看下?是不是我的理解有问题。

没看过第四版,TIJ是十几年前看的了,当时就觉得翻译+原著都有点问题
智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



猜您在找
java基础—IO类——LineNumberReader 的使用 Java基础---Java---IO流-----LineNumberReader方法及原理、自定义一个LineNumberReader、字节流、图片复制、mp3复制、 Java基础知识强化之IO流笔记55:IO流练习之 自定义类模拟LineNumberReader的获取行号功能案例 Java中的装饰者模式、LineNumberReader、打印流(基础解析) 设计模式-装饰模式(Decorator)    一、概念   动态的给一个对象添加一些额外的职责,是继承关系的一个替代方案。 二、模式动机   有时希望给某个对象而不是整个类添加一些功能,我们需要精确的控制给这个对象添加功能的时机。使用继承机制也是添加功能的一种方法,但是它是静态的。如现在有一个类A和一个类B,如果类B产生的对像需要具备类A的功能,那么一种方法就是将类B继承于类A (Class B extends A ),那么类B的对象都将具有类A的功能,而无法做到在某些情况下类B的对象具有类A的功能,某些情况下不具备类A的功能(即类B的对象需要具有类A的功能时,可以动态的添加到类B的对象上)。而装饰模式就可以很好的解决这个问题,且对客户端是透明的。 三、模式的结构                角色职责:   Component:组件对象的接口,能给这些对象动态的添加职责   ConcreteComponent:具体组件对象,实现组件对象的接口,通常就是被装饰的原始对象,也就是可以给这个对象添加职责。   Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个componet成员,即被装饰的对象,该对象有可能已不是被装饰的原始对象,有可能是已被装鉓过的对象。   ConcreteDecoratorA:具体的装饰器对象,实现具体要向被装饰对象添加功能。     代码样例 :     package decorator.base; /** * 组件对象的接口,能给这些对象动态的添加职责 * @ClassName: Component * @author beteman6988 * @date 2018年1月20日 上午9:13:22 * */ public interface Component { public void operation(); } package decorator.base; /** * 需要添加职责的原始对象 * @ClassName: ConcreteComponent * @author beteman6988 * @date 2018年1月20日 上午9:28:52 * */ public class ConcreteComponent implements Component { @Override public void operation() { // 具体业务 System.out.println("对象的原始职责!"); } } package decorator.base; /** * 装饰器的抽象父类,持有一个指上组件对象的接口对象,并定义一个与组件接口一致的接口 * @ClassName: Decorator * @author beteman6988 * @date 2018年1月20日 上午9:37:02 * */ public abstract class Decorator implements Component { protected Component component; //指上组件对象的接口对象 public Decorator(Component component) { this.component = component; } public void operation() { this.component.operation(); //转发请收给组件对象 } } package decorator.base; /** * 具体装饰器,为组件对象添加职责 * @ClassName: ConcreteDecoratorA * @author beteman6988 * @date 2018年1月20日 上午9:53:47 * */ public class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } public void operation() { //调用父类的方法之前添加职责 System.out.print("添加职责A + "); super.operation(); //转调父类的方法 //调用父类的方法之后可以添加职责 } } package decorator.base; /** * 具体装饰器,为组件对象添加职责 * @ClassName: ConcreteDecoratorB * @author beteman6988 * @date 2018年1月20日 上午9:52:21 * */ public class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } public void operation() { //调用父类的方法之前添加职责 System.out.print("添加职责B + "); super.operation(); //转调父类的方法 //调用父类的方法之后可以添加职责 } } package decorator.base; public class Client { public static void main(String[] args) { Component component=new ConcreteComponent(); //原始组件对象 Component componentA=new ConcreteDecoratorA(component); //给原始组件对象添加职责A componentA.operation();//这时componentA对象就具有了组件A的职责和原始组件的职责 Component componentB=new ConcreteDecoratorB(component); //给原始组件对象添加职责B componentB.operation(); //这时componentB对象就具有了组件B的职责和原始组件的职责 Component componentC=new ConcreteDecoratorB(componentA); //给组件A对象添加职责B componentC.operation(); //这时componentC对象就具有了组件B的职责+组件A的职责+原始组件的职责 } }View Code 运行结果: 添加职责A + 对象的原始职责! 添加职责B + 对象的原始职责! 添加职责B + 添加职责A + 对象的原始职责!    半透明的装饰模式    如代码样例所示,针对客户端使用的只是一个Component的接口对象,对客户完全是透明的。而这样纯粹的装饰模式在现实生活中其实很难找到的,装饰模式的用意是在不改变接口的前提下,增强所考虑的类的功能。在增强功能的时候,往往需要增加接口中并没有声明过的新的方法 ,换言之,也就是允许装饰模式改变接口,这就是半透明的装饰模式。下面以JDK中的I/O类进行分析如下:       角色分析:     Component: InputStream组件     ConcreteComponent:FileInputStream,读取Byte文件流     Decorator:FilterInputStream ,抽像装饰类     ConcreteDecorator:LineNumberInputStream ,带跟踪行号的字节输入流,可以通过getLineNumber()得到当前输入流的行号   从上面可以看出LineNumberInputStream 是一个半透明的装饰模式,getLineNumber()方法在InputStream接口组件中并不存在,如果想用这个方法就必须用具体的LineNumberInputStream 类,如下例子:       import java.io.FileInputStream; import java.io.InputStream; import java.io.LineNumberInputStream; public class TestLineNumberInputStream { public static void main(String[] args) { try { InputStream is=new FileInputStream("i:\\aa.txt"); LineNumberInputStream lis=new LineNumberInputStream(is); //InputStream lis=new LineNumberInputStream(is); /** 如果这样定义,则下面的int lineNum=lis.getLineNumber(); 将无法使用 因为 InputStream并没有这个方法 boolean flag=true; do{ byte[] array=new byte[1024]; int lineNum=lis.getLineNumber(); for(int i=0;i<1024;i++) { byte b= (byte) lis.read(); if(b== -1 ||b==10 ) { String s=new String(array,"GBK"); System.out.println("第"+lineNum+"行"+" : "+s); if(b== -1) { flag=false; } break; }else { array[i]=b; } } }while(flag); } catch (Exception e) { e.printStackTrace(); } } }View Code  运行结果为:      模式简化一、     如果只有一个ConcreteComponent,那么就没有必要定义一个Component组件接口,这时Decorator直接继承至ConcreteComponent即可,如下图:        模式简化二、     如果具体装饰角色只有一个或者不多于两个,那么Decorator也是可以省略的,如下图所示:        四、模式样例     通过JAVA I/O中的Reader、InputStreamReader、BufferedReader、LineNumberReader来分析装饰模式:     每个类的角色     Component: Reader ,用于读取字符流的顶层抽象类,继承于该类的子类都具有读取字符流的能力。     ConcreteComponent:InputStreamReader,它是字节流到字符流的转换类,是字节流通上字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。它的Read()方法可以每次读取一个字符(每个文件在磁盘上都是以一定的二进制序列进行存储,以什么样的二进制进行存储,则要跟据文件存盘时选定的编码来决定,如一个文本文件中只有一个“a”字符,如果以utf-8 编码进行存储,那么他在磁盘上的二进制编码为“1100001”,一个byte8个bit位。如果以utf-16编码进行存储,则二进制为“11111110111111110000000001100001”,4个字节32个bit位,其中前2个字节16个bit位表示大小尾序。InputStreamReader首先通过传给他的InputSream对象读取到该InputStream中的二进制Byte位,如果将这些二进制的字节转换成正确的字符,那么就必须用存盘时的编码进行逆向解码,所以InputStreamReader的构造函数需要指定解码用的字符集,如果没有指定则用平台默认字符集进行解码)。     Decorator:BufferedReader,具有缓冲功能的字符流读取类,在上面的类图中我们看不到他持有的一个Reader接口类成员,因为它的Reader接口类成员是私有的。但它确实拥有一个Read接口类成员,该类可以看做一个Decorator,因为他是一个非抽象类,它也可以看做一个ConcreteDecorator,从他的做用“具有缓冲功能的字符流读取类”就可以看出,它对它持有的Reader接口对象增加了缓冲功能,如它拥有readLine方法,可以一行一行的的读取字符。     ConcreteDecorator:LineNumberReader,可以在字符流读取时,得到字符所在行号。如上面的类图,它可以给InputStreamReader增加读取行号功能。     综合分析:         Reader抽像类,字符流的父类,继承于它的子类都可以以字符方式进行读取字符。         InputStreamReader:可以从二进制流中以单个字符的方式读取字符.         BufferedReader:对持有的Reader接口对象进行装饰,增加缓冲功能,可以一行一行的读取字符。                             LineNumberReader:具体装饰对象,增加读取行号的功能。                                public class TestInputStreamReader { public static void main(String args[]) { try { InputStream is=new FileInputStream("i:\\aa.txt"); Reader isReader=new InputStreamReader(is,"GBK"); //将BufferedRead看成ConcreteDecorator /*BufferedReader br=new BufferedReader(isReader); //BufferedReader对InputStreamReader进行装饰 String aLine=br.readLine(); System.out.println(aLine); aLine=br.readLine(); System.out.println(aLine);*/ //将BufferedRead看成Decorator LineNumberReader lineNumReader=new LineNumberReader(isReader); int lineNum=lineNumReader.getLineNumber(); String s=lineNumReader.readLine(); System.out.println("第"+lineNum+"行:"+s); lineNum=lineNumReader.getLineNumber(); s=lineNumReader.readLine(); System.out.println("第"+lineNum+"行:"+s); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }View Code 运行结果如下: 第0行:我是中国人 第1行:我深深的爱着我的祖国   五、与其它模式的关系   装饰模式和适配器模式:二者都有一个别名---wrapper模式,但是这两个模式是很不一样的模式,适配器模式的用意是要改变所考虑对象的接口而不一定要改变对象的性能,适配器模式把一个API转换在另一个API,而装饰模式的用意是要保持接口,即保持被包装对象的API,从而增强所考虑对象的性能。  六、模式优缺点   优点:    1.比继承更加灵活:继承是静态,而且一旦继承所有的子类都有一样的功能,而装饰模式模式采用把功能分离到每个装饰器中,然后通过对象组合的方式,在运行时动态的组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能来决定的。    2.更加容易复用:可以给一个对象增加多个同样的装饰器,也可以用一个装饰来装饰不同的对象,从而实现复用装饰器的功能。   缺点:因为一般一个装饰器只实现一个功能,为了增强一个对象的功能可能需要很多不同功能的装饰器进行多次的装饰,所以会产生很多细粒度的对象。   posted on 2018-01-21 21:22 bateman6988 阅读(...) 评论(...) 编辑 收藏
 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告