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的时候就返回这个暂存的值。读取一个字节会判断其是否是\n,是行号就直接加1了,如果是\r,就让pushBack再读一个,如果是\n就重置为-1。这段写的很绕,通俗的说就是:read()方法是读取一个字节,我们都知道流读取了就不能再读取,但是判断换行符的时候就麻烦了,\r的时候需要判断一下下一个是否是\n,所以需要再读取一个字节,这个时候就要保存一下这个字节了,就存在pushback中,pushback一般都是-1,意味着直接读一个就可以了,不是-1的时候就是说之前判断的是\r,但下一个不是\n,所以保存了一下这个非\n的字符,本次就直接返回了。上面有一个坑的地方,其判断了\r之后就还会执行\n,因为没有break。这会造成下例效果:

    @Test
	public void test() throws IOException {
		ByteArrayInputStream bais = new ByteArrayInputStream("123\r\t\n456\r\n789\r\n".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());
	}

  多出现了一个空行。实际上面确实\r\t\n,这个产生了两个回车,实际上直接输出也是两个回车。(-。-)!!!可能废弃的真正原因就如上所说的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变成原有的值。我个人是这么理解的。如有错误,请指教一下。

时间: 2024-08-25 06:09:08

Java之IO(九)其它字节流的相关文章

java的IO流,字节流和字符流

java操作文件都是通过流来处理的,(其实其他很多语言也是这样) 第一:java的IO流,分为:输入流 和 输出流(这真是废话,这是从流向的角度来说的) 第二:java的所有IO流,只分为:字节流 和 字符流(其实就是传输的颗粒,传输的基本单位) 总结:凡是处理纯文本的优先考虑字符流:其他的才考虑使用字节流

java的IO操作:字节流与字符流操作

流的概念 程序中的输入输出都是以流形式,流中保存的实际上都是字节文件. 字节流与字符流 字节流的操作: 1)输入:inputStream, 2)输出:outPutStream; 字符流的操作: 1)输入主要使用:write类. 2)输出主要使用:reader类. 内容操作就四个类. 操作流程: 使用File类操作一定有路径问题,注意分隔符: 实际上四个操作类都是抽象类(区别接口,抽象类的成员都是抽象,并且只能单继承,接口可以有全局变量,但是接口可以多继承) IO操作属于资源操作,对于资源操作,操

JAVA 19 IO流之字节流

字节流两个基类 InputStream  读 OutputStream   写 字符流的两个基类 Reader Writer 这四个抽象类派生出来的子类都是以其父类名作为子类后缀的 OutputStream 基本方法: close() flush() write()   参数为:byte[]  b,int b InputStream 基本方法 read() int avaliable()   返回文件中的剩余字节个数.即文件大小,这样就可以定义一个数组来恰好装下数据.但是数据量太大不可以这样用

【java】io流之字节流转为字符流:java.io.OutputStreamWriter和java.io.InputStreamReader

1 package 文件操作; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.OutputStream; 7 import java.io.OutputStreamWriter; 8 9 public class TestOutputStreamWriter { 10 public static void main(String[

Java之IO初识(字节流和字符流)

IO概述 生活中,你肯定经历过这样的场景.当你编辑一个文本文件,忘记了 ctrl+s ,可能文件就白白编辑了.当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里.那么数据都是在哪些设备上的呢?键盘.内存.硬盘.外接设备等等.我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为 输入input 和 输出output ,即流向内存是输入流,流出内存的输出流.Java中I/O操作主要是指使用 java.io 包下的内容,进行输入.输出操作.输入也叫做读取数据,输

【Java】IO流--文件字节流--FileInputStream、FileOutputStream

FileInputStream 作用: 文件系统中的文件获取输入字节. 什么文件可用取决于主机环境.用于读取诸如图像数据的原始字节流. 构造方法: FileInputStream(File file) 通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名. FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名. 常用方

java的IO学习,字节流与字符流的编码讲解

字节流与字符流 字节流可以处理所有类型的数据(图片.视频等),在java中对应的类都为“stream”结尾 1字节=8位二进制=具体存储空间 字符流仅能处理纯文本的数据,在java中对应的类都是以“reader”或者“writer”结尾 如汉字,符号等 import org.junit.Test; public class IOTest { /** * BufferedInputStream BufferedOutputStream * 利用字节缓冲流实现文件的复制 * @throws IOEx

java之IO流(字节流)

一.字节输出流OutputStream OutputStream此抽象类,是表示输出字节流的所有类的超类.操作的数据都是字节,定义了输出字节流的基本共性功能方法. 输出流中定义都是写write方法: close():关闭此输出流并释放与此流有关的所有系统资源 flush():刷新此输出流并强制写出所有缓冲的输出字节 write(byte[] b):将b.length个字节从指定的byte数组写入此输出流 write(byte[] b,int off,int len):将指定byte数组中从偏移量

Java文件(io)编程——文件字节流的使用

案例1: 演示FileInputStream类的使用(用FileInputStream的对象把文件读入到内存) 首先要在E盘新建一个文本文件,命名为test.txt,输入若干字符 1 public class Demo_2 { 2 3 public static void main(String[] args) { 4 File f=new File("e:\\test.txt"); //得到一个文件对象f,指向e:\\test.txt 5 FileInputStream fis=nu