本文共 4361 字,大约阅读时间需要 14 分钟。
Java中的IO流主要分为:四种(8个主要相关的类,其中前4个为顶级类) 按流向分:输入流和输出流 按性质分:原始流和装饰流 按类型分:字节流和字符流 1.原始字节流,inputstream和outputstream, 用于读取诸如图片,视频,音频等的原始字节文件,一个一个字节读,效率低。 2.在字节流的基础上使用IuputStreamReader装饰成的字符流,reader和writer。 文件中包含汉字等非单字节字符时使用,一个字符一个字符读,效率低。 3.在原始字节流的基础上装饰的带缓存的字节流。BufferedInputStream,BufferedOutputStream。 带缓存的一个字节一个字节读,可以用来读取原始的图片等数据,替换原始的InputStream,效率高。 4.在字符流的基础上装饰的带缓存的字符流。BufferedReader和BufferedWriter,分别新增readLine()和newLine()方法, 一个缓存一个缓存读,效率高。 --------------------------------------------------------- 输出流特例 --- 2种打印流 PrintStream(字节输出流) -- 在其他输出流的基础上添加了许多新的功能。 1.没有对应的输入流 2.可以写入:基本数据类型,字符串,对象,数组等所有的数据类型 3.带有自动行刷新功能,但必须在构造方法中开启刷新功能,默认不带有刷新功能。 4.在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。 5.PrintStream虽然是操作字节的,但是因为具有println等换行功能,所以不能用来写入原始的图片,音频等数据。 System.out(标准输出:默认输出到控制台):返回的是PrintStream类的实例 System.in(标准输入:默认为键盘):返回的是InputStream类的实例 System.err(标准错误输出流:默认红色输出到控制台)三者均返回的是PrintStream类的实例。 这些默认的输入输出位置可以使用System类中的setIn(),setOut(),setErr()方法来更改设置: 如更改输出位置为指定文件: //指定输出流位置: System.out.println("我被输出到控制台!"); System.setOut(new PrintStream("E://test//test1.txt")); System.setErr(new PrintStream("E://test//test2.txt")); System.out.println("我被输出到指定的位置!!"); System.err.println(我被输出到test2.txt文件); //指定输入流位置 System.setIn(new InputStream("E://test//test.txt")); InputStream in = System.in; //从该输入流in中获取数据 byte[] buffer = new byte[1024]; int length = -1; while((length = in.read(buffer)) != -1){ System.out.println(new String(buffer,0,length)); } ---------------------------------------------------------- PrintWriter(字符输出流) 1.在BufferedWriter上的再一次封装,即在原始字节输出流上的三次装饰。 PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new OutputStream("E://test.txt"))); 2.默认不带自动刷新功能,可通过第二个参数指定,如果指定为true,那么println、printf 或 format 方法将刷新输出缓冲区 3.可以写入基本数据类型,对象,数组,字符串等所有的数据。 两者中建议使用PrintWriter ----------------------------------------------------------- 不使用Scanner,读取键盘录入??? 第一种方式,一个字节一个字节读: InputStream in = System.in; //读取流 Byte[] buffer = new byte[1024]; int length = -1; while((length = in.read(buffer))!=-1){ System.out.println(new String(buffer,0,length)); } 第二种方式:因为用户可能会输入汉字,所以应该使用字符流: InputStream in = System.in; Reader reader = new InputStreamReader(in); //读取流 char[] buffer = new char[1024]; int length = -1; while((length = reader.read(buffer))!=-1){ System.out.println(new String(buffer,0,length)); } 第三种方式:带缓存的字符流,可以按行读取,并且高效 InputStream in = System.in; BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String str = ""; while((str = reader.readLine())!=null){ System.out.println(str); } ------------------------------------------------------------------------------------ 以上获取到str之后,使用带缓存的字符流读取到的是字符串,可以实现字符串和基本数据类型之间的转换, 然后就可以获取到基本数据类型的结果,就达到了和Scanner一样的效果,查看Scanner源码实现。 --------------------------------------------------------------------------------------- 模拟系统Scanner类编写自己的MyScanner类的思路: -------------------------------------------------------------------------------------------------------- Object流:用来传输对象信息,包括字符串和数组,并且一次可以写入多个对象,在取时顺序和类型与写入时一致。 例如用户登录时可以将用户名和密码封装成一个JavaBean对象,将该对象的信息保存到本地的.tmp文件中。 使用场景:在main方法中,创建一个Person对象,给各属性赋值完了之后将该对象信息保存到本地的.tmp文件中。 使用条件: 1.该对象要实现Serializable接口可序列化 2.可以写入各种类型的数据。 3.不能序列化静态变量 4.如果存储了多个对象,那么取出顺序和存入的顺序一致 对象的写又被称为:序列化 对象的读又被称为:反序列化 对象输出流:ObjectOutputStream对象的创建: 对象输入流:ObjectInputStream 扩展:所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性, 根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此, 为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。 还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能), 原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。 ---------------------------------------------------------------------------------------------------- Data流:用来写出和读入基本数据类型,读取的顺序与写入的顺序一致。 ------------------------------------------------------------------------------------------------------ 内存流: 流的源和目的地除了可以是文件外,还可以是计算机内存。 字节输入流ByteArrayInputStream和字节输出流ByteArrayOutputStream分别使用字节数组作为流的源和目标。 //从网络获取数据使用内存流,数据大小,类型不确定 public static byte[] read(InputStream input) throws Exception{ ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; //read方法的返回值为int类型的数据,如果返回-1代表数据读取完 int len = 0; //使用while循环将数据读取到一个字节数组中 while((len = input.read(buffer)) != -1){ //一边读一边存放数据 out.write(buffer, 0, len); } //关闭流 input.close(); //返回内存中的数据 return out.toByteArray(); } 使用的目的:将网络文件读取缓存到内存中,以后每次读取直接从内存中读取,节省了流浪和时间,也可以快速获取。
转载地址:http://khtjz.baihongyu.com/