从不同的角度对流可以分为以下几类:
1、输入流和输出流
输入流:只能从文件中读取数据,而不能向其中写入数据。 输出流:只能向文件中写入数据,而不能读取。 如从服务器通过网络传送数据到客户端,Server端的内存负责将数据输出到网络上,因此Server端的程序使用的是输出流。Client端的内存负责从网络上读取数据,因此Client端的程序使用的是输入流。 2、字节流和字符流 引用(http://www.2cto.com/kf/201312/262036.html) 字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的流对象。本质就是基于字节流读取时,去查了指定的码表。 字符流和字节流的而不同点: 1、读取单位不同:字节流以字节byte(8bit)为单位,字符流以十六位的字符操作单位。 2、处理对象不同:字节流能处理所有类型的数据(如图片、视频等),而字符流只能处理字符类型的数据。 3、字节流在操作的时候本身是不会用到缓冲区的,是对文件本身进行直接操作;而字符流在操作的时候会用到缓冲区,是通过缓冲区来操作文件。 结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容,但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。 规律:后缀是Stream的都是字节流,后缀是Reader、Writer的是字符流。 3、节点流和处理流 按照角色进行分类。 可以直接的向一个IO设备(磁盘/网络)读/写数据的流就是节点流,也被称之为低级流。 处理流用于对已存在的流记性连接和封装,通过封装后的流实现数据的读/写功能,也被称作高级流。 java中的流是通过四个基类派生而来: InputStream(字节输入流) Reader(字符输入流) :所有输入流的基类。 OutputStream(字节输出流) Writer(字符输出流) :所有输出流的基类。 具体分析各种流: 1、输入字节流 InputStream InputStream是所有的输入字节流的父类,它是一个抽象类。 ByteArrayInputStream、StringBufferInputStream、FileInputStream是三种基本的介质流,他们分别从Byte数组、StringBuffer和本地文件中读取数据。 实例代码:读取文件中的内容:FileInputStream:
[java] view plain copy print ? package com.basic.file; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class FileInputStreamDemo { public static void main(String[] args) { File file=new File("c:\\a.txt"); FileInputStream fis=null; try { //创建文件输入字节流 fis=new FileInputStream(file); //创建一个用于缓存字节数组 byte[] by=new byte[1024]; //定义一个int型变量,用于记录读入的字节数 int len=0; //循环获取数据 while((len=fis.read(by))!=-1){ //把字节数组转换成字符串输出 System.out.println(new String(by,0,len)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
代码中by的字节长度为1024,如果文件较小的话,则会造成浪费空间,我们需要文件的准确大小,这是我们可以把 byte[] by=new byte[1024];===>byte[] by=new byte[(int) file.length()]; 按字节读取文件中的内容:
代码示例:[java] view plain copy print ? package com.basic.file; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class FileInputStreamDemo { public static void main(String[] args) throws IOException { File file=new File("c:\\a.txt"); FileInputStream fis=null; fis=new FileInputStream(file); byte[] by=new byte[(int) file.length()]; int len=0; int count=0; while((len=fis.read(by))!=-1){ by[count++]=(byte) fis.read(); System.out.println(new String(by)); if(fis!=null){ fis.close(); } } } } 2、输出字节流 OutputStream OutputStream是所有输出字节流的父类,它也是一个抽象类。ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
向文件中写入字符串的代码示例: 代码示例:
[java] view plain copy print ? package com.basic.file; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamDemo { public static void main(String[] args) { File file=new File("c:\\b.txt"); FileOutputStream fos=null; try { fos=new FileOutputStream(file); fos.write("哈哈哈哈哈哈哈哈".getBytes()); fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 输入字节流读取文件的步骤: 1、创建一个输入文件字节流的对象。 2、创建一个字节数组用于缓存数据。 3、创建一个用于保存读取字节数的变量。 4、循环读取数据。 5、把字节数组转换成字符串等格式。 6、关闭流。 输出字节流写入文件的步骤: 1、创建一个输出文件字节流对象。 2、准备数据源,把数据源转换成字节数组。 调用write方法,把数据源内容写入到输出流当中。 4、刷新流。 5、关闭流。 利用字节输入流和字节输出流进行文件的复制: 代码示例:
[java] view plain copy print ? package com.basic.file; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class CopyDemo1 { public static void main(String[] args) { copy(new File("c:\\a.txt"),new File("c:\\b.txt")); } public static void copy(File srcFile,File destFile){ FileInputStream fis=null; FileOutputStream fos=null; try { fis=new FileInputStream(srcFile); fos=new FileOutputStream(destFile); byte[] by=new byte[1024]; int len=0; while((len=fis.read(by))!=-1){ fos.write(by, 0, len); fos.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { fos.close(); fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3、字符输入流 Reader Reader是所有的输入字符流的父类,它是一个抽象类。 CharReader、StringReader是两种介质流,它们分别将Char数组和String中读取数据。 BufferedReader为Reader提供缓冲功能。 4、字符输出流 Writer Writer 是所有的输出字符流的父类,它是一个抽象类。BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
节点流处于io操作第一线,所有的操作必须通过它来进行,处理流对于其他流进行操作(提高效率和操作灵活性)。 处理流不断地增大了处理的范围,对于其他流的处理提高了性能、效率和操作的灵活性。 处理流中的分类: 一:缓冲流 1、字节缓冲流 BufferedInputStream BufferedOutputStream 2、字符缓冲流 BufferedReader BufferedWriter
BufferedInputStream实现的原理: 其中有一个缓存区间,默认大小为8kb,每次调用read方法时,会先尝试从缓存区当中获取内容,如果读取失败就说明缓存区没有数据,然后把这些字节放入放入缓存区当中,最后再将缓存区的内容或者全部缓存给用户,直接从缓存区读取数据会比直接从数据源读取数据的速度快,所以效率更高,性能更好。 如果没有缓冲区,read()没执行一次,就会发送一次I/O操作。 二:转换流 作用:将字节流转换成字符流,乱码、编码和解码的问题。 1、编码和解码的概念: 解码就是二进制的内容通过解码字符集转换成字符的过程。 编码就是字符通过编码字符集转换成二进制内容的过程。 乱码出现的原因: 1、编码和解码的字符集不统一。 2、字节的缺少,长度的丢失。 三:内存流或者字节数组流 ByteArrayInputStream 字节数组输入流 ByteArrayOutputStream 字节数组输出流 四:数据处理流 DataInputStream DataOutputStream 既能保存数据,又能保存数据类型。 只能保留基本类型+String 五:序列化流 ObjectInputStream ObjectOutputStream 保留引用数据(对象) 数据+类型 序列化和反序列化 序列化:将对象保存在文件里或者保存在字节数组当中。 把对象转换为字节序列的过程称为对象的序列化。 反序列化:将文件或者字节数组转换成对象。 将字节序列恢复成对象的过程称为对象的反序列化。 注意: 1、先序列化再反序列化,反序列化的顺序必须和序列化的顺序相同。 2、不是所有的对象都可以被序列化,只有实现了Serializable这个接口的类才可以被序列化。 3、不是所有的属性都需要被序列化,用transient修饰。 对象序列化的功能: 1、把对象的字节序列永远的保存在硬盘上,通常会存放在一个文件中。 2、在网络上传送对象的自己序列。 反序列化: 输入流 objectInputStream 序列化: 输出流 objectOutputStream
对于I/O流这块,刚学的时候脑子里感觉都乱成一锅粥了,总结以下,感觉清晰了好多。