IO流
本博主要理论,具体实现比较少。
IO流
IO是什么:
IO流用来处理设备之间的数据传输。
Java程序中,对于数据的输入/输出操作以“流(Stream)”的方式进行。
流的分类:
按操作数据单位不同分为:字节流(8bit),字符流(16bit)
按数据流的流向不同分为:输入流,输出流。
按流的角色不同分类:节点流,处理流。
Java的IO流共涉及40多个类,都是由规则的,都是从上面图片中四个基类派生而来。
这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
IO应用场景:
输入input:读取外部数据(磁盘,光盘等存储设备的数据)到程序(内存中)。
输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
Java.io.File类的使用:
文件流:FileInputStream/FileOutputStream/FileWriter
缓冲流:BufferedInputStream/BufferedOutputStream/BufferedReader/BufferedWriter
具体对应如下图(非常重要,本人用IO流基本看此图):
File类的方法:
File基本操作:
File dir1 = new File("D:/IOTest/dir1"); if (!dir1.exists()) { // 如果D:/IOTest/dir1不存在,就创建为目录 dir1.mkdir(); } // 创建以dir1为父目录,名为"dir2"的File对象 File dir2 = new File(dir1, "dir2"); if (!dir2.exists()) { // 如果还不存在,就创建为目录 dir2.mkdirs(); } File dir4 = new File(dir1, "dir3/dir4"); if (!dir4.exists()) { dir4.mkdirs(); } // 创建以dir2为父目录,名为"test.txt"的File对象 File file = new File(dir2, "test.txt"); if (!file.exists()) { // 如果还不存在,就创建为文件 file.createNewFile(); } |
文件流:
读取文件:
1、建立一个流对象,将已存在的一个文件加载进流
FileReader fr=new FileReader(“Test.txt”);
2、创建一个临时存放数据的数组
Char[] ch=new char[1024];
3、调用流对象的读取方法将流中的数据读入到数组中
fr.read(ch);
FileReader fr = null; try{ fr = new FileReader("c:\\test.txt"); char[] buf = new char[1024]; int len= 0; while((len=fr.read(buf))!=-1){ System.out.println(new String(buf ,0,len));} }catch (IOException e){ System.out.println("read-Exception :"+e.toString());} finally{ if(fr!=null){ try{ fr.close(); }catch (IOException e){ System.out.println("close-Exception :"+e.toString()); } } }
|
写入文件:
1、创建流对象,建立数据存放文件
FileWriter fw=new FileWriter(“Test.txt”);
2、调用流对象的写入方法,将数据写入流
Fw.write(“test”);
3、关闭流资源,并将流中的数据清空到文件中。
Fw.close();
FileWriter fw = null; try{ fw = new FileWriter("Test.txt"); fw.write("text"); } catch (IOException e){ System.out.println(e.toString()); } finally{ If(fw!=null) try{ fw.close(); } catch (IOException e){ System.out.println(e.toString());} }
|
注意:
1、定义文件路径时,注意:可以使用“/”或“\\”
2、在写入一个文件时,如果目录下有同名文件将被覆盖
3、在读取文件时,必须保证该文件已存在,否则异常
缓冲流:
1、为了提高数据读写速度,java提供了缓冲功能的流,使用缓冲流时,会创建一个内部缓冲区数组。
2、根据数据操作把缓冲流分为分为:
BufferedInputStream和BufferedOutputStream
BufferedReader和BufferedWriter
3、缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了新的方法。
4、对于输出的缓冲流,写出的数据会现在内存中缓存,使用flush()将会使内存中的数据立刻写出。
BufferedReader br = null; BufferedWriter bw = null; try { //step1:创建缓冲流对象:它是过滤流,是对节点流的包装 br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt")); bw = new BufferedWriter(new FileWriter("d:\\IOTest\\destBF.txt")); String str = null; while ((str = br.readLine()) != null) { //一次读取字符文本文件的一行字符 bw.write(str); //一次写入一行字符串 bw.newLine(); //写入行分隔符 } bw.flush(); //step2:刷新缓冲区 } catch (IOException e) { e.printStackTrace(); } finally { // step3: 关闭IO流对象 try { if (bw != null) { bw.close(); //关闭过滤流时,会自动关闭它所包装的底层节点流 } } catch (IOException e) { e.printStackTrace(); } try { if (br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } |
转换流:
1、转换流提供了在字节流和字符流之间的转换
2、JavaAPI提供了两个转换流:
2.1、InputStreamReader
用于将字节流中读取到的字节按照指定字符集解码成字符,需要和InputStream“套接”
public InputStreamReader(InputStream in)
public InputSreamReader(InputStream in,String charsetName)
2.2、OutputStreamWriter
用于将要写入到字节流中的字符按指定字符集编码成字节。需要和OutputStream“套接”构造方法
public OutputStreamWriter(OutputStream out)
public OutputSreamWriter(OutputStream out,String charsetName)
3、字节流中的数据都是字符时,转换成字符流操作更高效
public void testMyInput() throws Exception{ FileInputStream fis = new FileInputStream("dbcp.txt"); FileOutputStream fos = new FileOutputStream("dbcp5.txt");
InputStreamReader isr = new InputStreamReader(fis,"GBK"); OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
BufferedReader br = new BufferedReader(isr); BufferedWriter bw = new BufferedWriter(osw);
String str = null; while((str = br.readLine()) != null){ bw.write(str); bw.newLine(); bw.flush(); } bw.close(); br.close();} |
标准输入输出流:
1、System.in和System.out分别代表了系统标准的输入和输出设备
2、默认输入设备是键盘,输出设备是显示器
3、System.in的类型是InputStream
4、System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream 的子类
5、通过System类的setIn,setOut方法对默认设备进行改变。
public static void setIn(InputStream in)
public static void setOut(PrintStream out)
打印流:
在整个IO包中,打印流是输出信息最方便的类。
1、PrintStream(字节打印流)和PrintWriter(字符打印流)
提供了一系列重载的print和println方法,用于多种数据类型的输出
PrintStream和PrintWriter的输出不会抛出异常
PrintStream和PrintWriter有自动flush功能
System.out返回的是PrintStream的实例
FileOutputStream fos = null; try { fos = new FileOutputStream(new File("D:\\IO\\text.txt")); } catch (FileNotFoundException e) { e.printStackTrace(); }//创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区) PrintStream ps = new PrintStream(fos,true); if (ps != null) { // 把标准输出流(控制台输出)改成文件 System.setOut(ps);} for (int i = 0; i <= 255; i++) { //输出ASCII字符 System.out.print((char)i); if (i % 50 == 0) { //每50个数据一行 System.out.println(); // 换行 } } ps.close(); |
数据流:
1、为了方便地操作Java语言的基本数据类型的数据,可以使用数据流。
2、数据流有两个类:(用于读取和写出基本数据类型的数据)
DataInputStream 和 DataOutputStream
分别“套接”在 InputStream 和 OutputStream 节点流上
3、DataInputStream中的方法
boolean readBoolean() byte readByte() char readChar() float readFloat() double readDouble() short readShort() long readLong() int readInt() String readUTF() void readFully(byte[] b)
|
例子:
DataOutputStream dos = null; try { //创建连接到指定文件的数据输出流对象 dos = new DataOutputStream(new FileOutputStream( "d:\\IOTest\\destData.dat")); dos.writeUTF("ab中国"); //写UTF字符串 dos.writeBoolean(false); //写入布尔值 dos.writeLong(1234567890L); //写入长整数 System.out.println("写文件成功!"); } catch (IOException e) { e.printStackTrace(); } finally { //关闭流对象 try { if (dos != null) { // 关闭过滤流时,会自动关闭它包装的底层节点流 dos.close(); } } catch (IOException e) { e.printStackTrace(); } } |
对象流:
1、ObjectInputStream和OjbectOutputSteam
用于存储和读取对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
2、序列化(Serialize):用ObjectOutputStream类将一个Java对象写入IO流中
3、反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象
4、ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
对象的序列化:
1、对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象
2、序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原
3、序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是 JavaEE 平台的基础
如果需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
Serializable
Externalizable
4、凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID;
serialVersionUID用来表明类的不同版本间的兼容性
如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的源代码作了修改,serialVersionUID 可能发生变化。故建议,显示声明
5、显示定义serialVersionUID的用途
希望类的不同版本对序列化兼容,因此需确保类的不同版本具有相同的serialVersionUID
不希望类的不同版本对序列化兼容,因此需确保类的不同版本具有不同的serialVersionUID