关于流的概念
Java 由流来完成具体的IO操作,虽然面对的是不同的外设(网络、鼠标、键盘)IO流使用与全部的外设,在底层Java已经将具体与物理设备交互的细节都处理好了。
流的分类:
从功能上
输入流:从外部到程序
输出流:从程序到外部
注意所谓的输入以及输出是相对于程序而言的,这一点很关键,在流类互相嵌套的时候千万要把握好这一点。
从结构上
字节流和字符流(字符流实际上是对字节流的封装)
字节流最低层的两个抽象类是 inputStream 以及 outputStream
字符流最低层的两个抽象类是 Reader 以及 Writer
还可以有其他的分类方式
节点流:从特定的地方进行读写的流,直接与目标进行交互。例如从磁盘或者内存的一块区域来进行读写。
过滤流:使用节点流或者过滤流作为输入或者输出,使用一个已经存在的输入或者是输出创建的流类。
通常的数据读写的相关逻辑:
1、 open a stream
2、 while more information(一边进行读写操作一边进行判断)
3、 read(write) information
4、 close information(比较重要 易忽略)
字节流相关
抽象类inputStream以及outputStream定义了实现其他类的关键方法,最主要的是read以及write方法,两种方法分别在inputStream以及outputStream中被定义,并且被派生类所重写,这些从inputStream与outputStream派生出来的类会针对不同的外设来进行处理。
三个主要的read方法
1、abstract int read()
2、int read(byte[]b)
3、int read (byte[]b,int offset,int len)
2,3 两个read 方法通过继承1 的read方法来实现,具体不同的类会有不同的read实现方法。
FileinputStream的演示(输入流的最一般的组普通的表示形式):
package com.file.fileInputStream; import java.io.*; public class fileInputStreamtest { public static void main(String[] args) throws Exception { InputStream is = new FileInputStream("F:\filetest.txt"); // 一次取200个字符 byte[] buffer = new byte[200]; int length; // read(Byte[]b (字节数组即目标数组),int offset(目标数组起始偏移),int len(每次读取的字字节的长度)) // 注意read方法 要是流已经读完了 就会返回-1 要是没读完就会返回读入buffer的字节数目 while (-1 != (length = is.read(buffer, 0, 200))) { // 将字符数组转化为子付串 String str = new String(buffer, 0, length); System.out.println(str); } // 关闭流 is.close(); } }
这里要注意buffer指定的大小的问题,因为汉字的情况下,按照默认的编码方式(GBK)是两个字节表示一个汉字,要是把buffer的大小设置成一个比较小的奇数比如 3 最后输入汉字的时候 很容易出现乱码,一般把大小设置成1024 2048 这个样子的,都是2的倍数。
字符流inputstream的所有的子类:
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream
字符流outputstream的所有的子类:
ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream
字符流中的节点流与过滤流:
节点流 直接与目标文件打交道 比如 FileOutputstream
过滤流 用于对节点流进行包装 减少IO的次数
下面的一个例子是用节点流将数据读入文件再用过滤流将数据从文件中读出:
package com.bytestream.bufferinput; import java.io.*; public class bufferTest { public static void main(String[] args) throws Exception { OutputStream os=new FileOutputStream("F:\filetest.txt"); String str="helloworld "; //将字符串转化为字符数组 byte[]buffer=str.getBytes(); os.write(buffer); //想要追加内容 后面的true 表示以append的方式进行追加 OutputStream os2=new FileOutputStream("F:\filetest.txt",true); String str2="this is added information by append way"; os2.write(str2.getBytes()); os.close(); os2.close(); //利用过滤流 将文件中的内容写入到程序中 InputStream is=new FileInputStream("F:\filetest.txt"); InputStream bis=new BufferedInputStream(is); byte[]b=new byte[200]; int length; while(-1!=(length=bis.read(b, 0, 128))){ //注意这里不能使用toString函数 只能是使用newstring生成一个新的string否则会是乱码 //具体的原因还不是太清楚 String bstr1=b.toString(); String bstr2=new String(b,0,length); System.out.println(bstr1); System.out.println(bstr2); } is.close(); bis.close(); } } 输出: [B@777d57d6 helloworld this is added information by append way
注意直接用toString转化byte数组再打印出来会出现乱码问题
其他的一些过滤流
ByteArrayInputStream以及ByteArrayoutputStream是将字节数组当做源实现输入和输出。
具体例子:
package com.bytestream.ByteArrayinputstreamtest; import java.io.*; public class bytearratInputstreamtest { public static void main(String[] args) throws Exception { String tmp="the test of bytearraystream"; byte[] b=tmp.getBytes(); ByteArrayInputStream bai=new ByteArrayInputStream(b); int c; for(int i=0;i<2;i++){ //采用这种方式是每次读一个字节 while(-1!=(c=bai.read())){ if(i==0) System.out.print((char)c); else //只能是英文情况下 System.out.print(Character.toUpperCase((char)c)); } //将一个流重读了一次 默认指向流最开始的位置 //相当于将bai流重置了 要是不加这个 即使设置了循环两次也还是无效的 bai.reset(); System.out.println(); } bai.close(); //利用bytearrayoutput将信息写入一个字符串 再利用fileoutputstream将信息写入 //注意与FileOutputStream区别 这个写入的目标对象是一个字符串而不是一个文件 ByteArrayOutputStream bao=new ByteArrayOutputStream(); String strout="test the ByteArrayOutputStream"; //将strout中的内容写入到这个ByteArayOutputStream输出流当中 //这个ByteArrayoutputstream中此时就已经存放了strout的信息 bao.write(strout.getBytes()); //将输出流转化成一个数组对象 byte[]result=bao.toByteArray(); for(int i=0;i<result.length;i++){ System.out.print((char)result[i]); } OutputStream os=new FileOutputStream("F:\filetest.txt"); //将ByteArrayOutputstream中的内容写入到一个文件输出流当中 bao.writeTo(os); os.close(); bao.close(); } } 输出结果: the test of bytearraystream THE TEST OF BYTEARRAYSTREAM test the ByteArrayOutputStream 对应的文件中(F:filetest.txt)也有了对应的信息
DataInputStream和DataOutputStream可以写入或者写出多种不同的数据类型的数据
package com.bytestream.DataStream; import java.io.*; public class DataStream { public static void main(String[] args) throws Exception { //通常的过滤流的定义方式 //以缓存的方式 将不同的数据写到一个文件中 DataOutputStream dos=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("F:\filetest.txt"))); byte b=3; int i=12; char c='a'; float f=3.3f; //每种数据类型都有对应着的不同写入模式 dos.writeByte(b); dos.writeInt(12); dos.writeChar(c); dos.writeFloat(f); dos.close(); //此时 filetest.txt中的内容肯定是乱码 因为每中类型的byte数目是不一样的 DataInputStream dis=new DataInputStream(new BufferedInputStream(new FileInputStream("F:\filetest.txt"))); //注意读出来的顺序应该与读进去的书序一样 这样才能保证正确恢复 System.out.println(dis.readByte()+" "+dis.readInt()+" "+dis.readChar()+" "+dis.readFloat()); } } 输出结果: 3 12 a 3.3
结果显示与输入的是一致的,要是不想这么麻烦,就将输入信息全转化为字符串,之后再输出。