IO(二)
- 字节流:以 8 位(即 1 byte,8 bit)作为一个数据单元,数据流中最小的数据单元是字节。
- 字符流:以 16 位(即 1 char,2 byte,16 bit)作为一个数据单元,数据流中最小的数据单元是字符, Java 中的字符是 Unicode 编码,一个字符占用两个字节。
一般会分成这两类。当然字符和字节之间是可以进行转换的,当然字节流可以读任何类型数据。毕竟协议不同,字节是一样的。
public static void main(String[] args) { char c = 'b'; byte[] b = new byte[2]; b[0] = (byte) ((c & 0xFF00) >> 8); b[1] = (byte) (c & 0xFF); for (byte b1 : b) { System.out.print(b1); } System.out.println(); char c1 = (char) (((b[0] & 0xFF) << 8) | (b[1] & 0xFF)); System.out.println(c1); }
根据协议的不同(UTF8,ASCII),不同的字符所占的字节会有所不同。
Java中有关流的四大顶级类
- InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
- OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
- Reader(文件格式操作):抽象类,基于字符的输入操作。
- Writer(文件格式操作):抽象类,基于字符的输出操作。
缓冲流:让数据在缓冲区能够减少系统实际对原始数据来源的存取次数,因为一次能做多个数据单位的操作。相较而言,对于直接从文件读取数据或将数据写入文件,比起缓冲区的读写要慢多了。所以使用缓冲区的流,一般都会比没有缓冲区的流效率更高。拥有缓冲区的流被称为缓冲流,包括BufferedInputStream、 BufferedOutputStream类和BufferedReader、BufferedWriter类。缓冲流把数据从原始流成块读入或把数据积累到一个大数据块后再成批写出,通过减少资源的读写次数来加快程序的执行。
具体实现的原理图解:
对象流:看网上的介绍一般可以用来游戏存盘等操作,我个人简单的理解就是将对象进行字符封装,也可以思考为转化为JsonObject然后toString然后进行持久化的思想。
public class IoDemo { public static void main(String[] args) throws Exception{ try { Person P=new Person("Jeccica",26); FileOutputStream fos=new FileOutputStream("C:\\Users\\admin\\Desktop\\Java\\temp\\22.txt"); ObjectOutputStream oos=new ObjectOutputStream(fos); oos.writeObject(P); oos.flush(); oos.close(); }catch(FileNotFoundException e) { e.printStackTrace(); }catch(IOException e) { e.printStackTrace(); } FileInputStream fis=new FileInputStream("C:\\Users\\admin\\Desktop\\Java\\temp\\22.txt"); ObjectInputStream ois=new ObjectInputStream(fis); Person P2=(Person)ois.readObject(); System.out.println(P2.name+"的年龄为"+P2.age); } } class Person implements Serializable{ String name=null; int age=0; Person(String _name,int _age){ name=_name; age=_age; } }
推回输入流:通常情况下使用输入流从磁盘、网络或者其它的物理介质读取数据都是按顺序读取的, 而在流的内部都会维护一个指针,读取数据的同时,指针会向后移动,直到读取完成为止。而在一些实际常见中,如果读出来的数据不是想要的,但又放不回去的时候怎么办?这时就可以使用IO提供的推回输入流。当使用普通的IO输入流如果读取到不想要的数据时,只能在程序里面处理掉,而使用IO里面的推回输入流读取数据则可以把数据给推回到输入流的缓冲区中。
public class IoDemo { public static void main(String[] args) throws IOException { //创建字符输入流 Reader reader1=new FileReader("E:/z/Ostrch.java"); //创建推回输入流 指定推回缓冲区大小为64, //如果不指定,默认缓冲区大小为1 PushbackReader reader=new PushbackReader(reader1,64); char[] cs =new char[32];//临时数组 int count=0;//读取的字符数 String strLast="";//记录上次读取的字符串 while ((count =reader.read(cs,0,cs.length))!=-1){ //本次读取内容 String str=new String(cs,0,count); //上次+本次读取内容--避免 要查找的字符串被截取 String StrContent=strLast+str; //查找目标字符串 //目标出现位置 int targetIndex =StrContent.indexOf("//字符型 char"); if(targetIndex>-1){ //找到目标字符串 //将本次内容和上次内容一起推回缓冲区 //*****推缓冲区的内容大小不能超过缓冲区的大小 reader.unread(StrContent.toCharArray()); //判断targetIndex 是否>32(临时数组大小) if(targetIndex>32){ cs=new char[targetIndex]; } //再次读取指定长度的内容(就是目标字符串之前的内容) reader.read(cs,0,targetIndex); str=new String(cs,0,targetIndex); System.out.println(str); break; }else{ //为找到目标字符串 //直接输出 System.out.println(strLast); strLast=str; } } } }
注意点:
1.字节流与字符流的不同是他们的处理方式,字节流是最基本的,采用ASCII编码。但是实际上很多数据是文本,所以提出字符流的概念,采用unicode编码。 两者之间通过inputStreamReader与outputStreamWriter来关联,实际上是通过byte[]与String来关联。
2.程序中所有的数据都是以流的方式进行传输与保存的。在关闭字符流后会强制性的将缓冲区的数据输出,若没有关闭缓冲区的内容是无法输出的,如果想不关闭并且还想输出缓冲区的内容,用writer类的flush()方法来完成。
3.Java对象的序列化指将一个java对象写入OI流中,与此对应的是,对象的反序列化则从IO流中恢复该java对象。如果要让某个对象支持序列化机制,则必须让它的类是可序列化的,为了让某个类是可序列化的,该类必须实现Serializable接口或Externalizable接口
4.Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片