zoukankan      html  css  js  c++  java
  • Java之IO(九)其它字节流

      转载请注明源出处:http://www.cnblogs.com/lighten/p/7063161.html

    1.前言

      之前的章节已经介绍了java的io包中所有成对(输入、输出对应)的字节流,本章介绍剩余的一些字节流,包括:LineNumberInputStream、SequenceInputStream、StringBufferInputStream。在JDK8的版本中,只有中间的SequenceInputStream没有被废弃,其它两个都被指出已废弃了。

    2.LineNumberInputStream

      这个输入流通过添加函数功能,能保持对输入流的行数的追踪。行号从0开始,每次增加1。顺便说一下,这个类是在JDK1.0就存在了。被废弃的原因在类的注释中也给出了:这个类错误地假设bytes能够足够表示characters。在JDK1.1中,也就是此类后面的版本,更好的方式来操作字符流就是创建一个新的字符流,这个流中包含了一个用于计算行号的类。这也就是在JDK1.1中出现的LineNumberReader,此节不讲,是字符流的内容。

      LineNumberInputStream继承于FilterInputStream,类结构如下:

      可以看出,对于抽象父类InputStream,其多了set和get行号的两个方法。下面先看基本的数据流的方法实现。

      之前看的结构图有四个变量,两个一组应该很好理解,mark开头的主要是让Inputstream的mark()方法使用,记录一下。lineNumber就是记录的行号了,pushBack有什么作用呢?看上图的read逻辑。pushBack默认情况下为-1,-1的时候就读取一个,不是-1的时候就返回这个暂存的值。读取一个字节会判断其是否是 ,是行号就直接加1了,如果是 ,就让pushBack再读一个,如果是 就重置为-1。这段写的很绕,通俗的说就是:read()方法是读取一个字节,我们都知道流读取了就不能再读取,但是判断换行符的时候就麻烦了, 的时候需要判断一下下一个是否是 ,所以需要再读取一个字节,这个时候就要保存一下这个字节了,就存在pushback中,pushback一般都是-1,意味着直接读一个就可以了,不是-1的时候就是说之前判断的是 ,但下一个不是 ,所以保存了一下这个非 的字符,本次就直接返回了。上面有一个坑的地方,其判断了 之后就还会执行 ,因为没有break。这会造成下例效果:

        @Test
    	public void test() throws IOException {
    		ByteArrayInputStream bais = new ByteArrayInputStream("123
    	
    456
    789
    ".getBytes());
    		LineNumberInputStream lnis = new LineNumberInputStream(bais);
    		byte[] buffer = new byte[1024];
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		int length;
    		while((length = lnis.read(buffer)) != -1) {
    			baos.write(buffer, 0, length);
    		}
    		System.out.println(new String(baos.toByteArray()));
    		System.out.println(lnis.getLineNumber());
    	}

      多出现了一个空行。实际上面确实 ,这个产生了两个回车,实际上直接输出也是两个回车。(-。-)!!!可能废弃的真正原因就如上所说的byte不能表示所有的字符吧。

     3.SequenceInputStream

      一个SequenceInputStream表示其他输入流的逻辑连接。它从一个有序的输入流开始,从第一个开始直到到达文件的末尾,然后从第二个文件中读取,以此类推,直到最后一个包含的输入流到达文件的末尾。

      这个流很简单,结构如下:

      就是接受了一组有序的输入流,读取的时候,一个个读到为罢了。

      像接力棒一样,读完一个又接一个,知道全部读取完毕。

        @Test
    	public void test2() throws IOException {
    		ByteArrayInputStream bais = new ByteArrayInputStream("你好".getBytes());
    		ByteArrayInputStream bais2 = new ByteArrayInputStream(",张三".getBytes());
    		SequenceInputStream sis = new SequenceInputStream(bais, bais2);
    		byte[] buffer = new byte[1024];
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		int length;
    		while((length = sis.read(buffer)) != -1) {
    			baos.write(buffer, 0, length);
    		}
    		System.out.println(new String(baos.toByteArray()));
    	}

    4.StringBufferInputStream

      这个流也是一个废弃的方法,其理由是:这个类不能正确地将字符转换成字节。在JDK 1.1中,从字符串创建流的首选方法是通过StringReader类。

      这个类允许应用程序创建一个输入流,其中读取的字节是由字符串的内容提供的。应用程序还可以使用ByteArrayInputStream从字节数组中读取字节。这个类只使用字符串中每个字符的低8位。结构也很简单:

      buffer就是缓存的字符串,count就是这个字符串的长度了。read()方法就是将字符串按字节读取:

      官方虽然给出了这两个流被废弃的原因,就是字符和字节之间的转换问题,但是个人还是不明白哪里会出问题,对编码还是所知甚少,目前最大的困惑就是所有的流都是以-1为结束标志符,C语言的文件流EOF也是-1,为什么不怕中间有个字节正好是-1呢?这里有篇文章说了一下这个问题:http://blog.csdn.net/jkler_doyourself/article/details/5645925。没有完全理解,但是-1是0xFFFFFFFF,而很多流读取的时候都&0xFF,测试如下:

        @Test
    	public void test3() {
    		byte[] a = new byte[]{-1};
    		ByteArrayInputStream bis = new ByteArrayInputStream(a);
    		System.out.println(bis.read());
    	}
    

      -1读出来是255。问题的根本在于并不是说读取到-1,主要的判断还是是否结束了,即再取值是否能取到,或者是已知其是否结束。这个方法才是判断流是否结束了,返回-1。而其它情况&0xFF之后就不会表现成-1了,-1是0xFFFFFFFF。这也是一个比较重要的手段。当然实际上值并没有改变,因为你再强转成byte又回到了-1,这里返回int也就规避了这个问题,取了int的0~255范围,所以你能够通过使用read()!=-1来判断结尾,再通过强转回byte变成原有的值。我个人是这么理解的。如有错误,请指教一下。

  • 相关阅读:
    CSS
    版权动态日记页脚 JS
    smoothscroll
    JavaScript String
    JavaScript Document对象
    【网易官方】极客战记(codecombat)攻略-森林-漫漫长路long-road
    【网易官方】极客战记(codecombat)攻略-森林-看门狗guard-dog
    【网易官方】极客战记(codecombat)攻略-森林-去拿过来go-fetch
    【网易官方】极客战记(codecombat)攻略-森林-宠物小测试pet-quiz
    【网易官方】极客战记(codecombat)攻略-森林-博士猫咪phd-kitty
  • 原文地址:https://www.cnblogs.com/lighten/p/7063161.html
Copyright © 2011-2022 走看看