基本内容
Process
1) 确定源
2) 选择流
3) 操作(读,写)
4) 释放资源.
分隔符
建议采用 "C:/JavaWork/asdf/xxx.java" 这种 /
无论是字节处理,还是字符处理, 都要套一层 buffer 来提升性能. (默认是 8k 做一次 I/O 的交互)
文件
File 类 用来定义源, 一般是本地文件
File src = new File("stanford.txt")
也可以直接用FileInputStream("stanford.txt") 这种来导入文件
字节码 处理 (文件copy)
字节可以处理一切文件, 无论是 视频,音频,文本.
InputStream & OutputStream -> BufferedInputStream & BufferedOutputStream, FileInputStream & FileOutputStream(直接字节流作用于文件)
package com.pratice.java300; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class MyByteCopy { public static void main(String[] args) { copyByte("stanford.txt", "xxx.txt"); } public static void copyByte(String src, String dest) { try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));){ byte[] temp = new byte[1024]; int len = -1; while ((len = bis.read(temp)) != -1) { bos.write(temp, 0, len); // 字节copy, 不用考虑换行符问题, 因为换行符包含在字节copy中 } }catch(IOException e) { e.printStackTrace(); } } }
把文件流封装在 try 的括号里边, 就不用释放资源了, 自动释放了.
字符处理 (文件copy)
只能处理文本
Reader & Writer -> BufferedReader & BufferedWriter, FileReader & FileWriter(直接字符流作用于文件)
package com.pratice.java300; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class MyCharCopy { public static void main(String[] args) { copyChar("stanford.txt", "xxx.txt"); } public static void copyChar(String src, String dest) { try(BufferedReader br = new BufferedReader(new FileReader(src)); BufferedWriter bw = new BufferedWriter(new FileWriter(dest));){ String msg = null; int line = 0; while ((msg = br.readLine()) != null) { if (0 == line) { line++; } else { bw.newLine(); } bw.write(msg, 0, msg.length()); } }catch(IOException e) { e.printStackTrace(); } } }
源并非文件实体, 而是内存, 例子中输出也是内存
字节数组流 ByteArrayInputStream 和 ByteArrayOutputStream, 因为这里不设计到 IO, 所以就没有 buffered。
ByteArrayInputStream 实际上是内存的一个内部缓冲区, 可以接受来自字节流的数据. 相当于读取到内存,转化成流处理,
我们都知道, 这里的文件处理都是 I/O 之间流的转换, 所以可以先通过 ByteArrayInputStream 将输入转换成流,缓存到内存中, 以备使用.
ByteArrayOutputStream 该类实现了将数据写入字节数组的输出流, 写出内存, 但是你想获得写出的数据, 需要使用 dest = baos.toByteArray()
可以将内存区缓存的内容读出到输出流来进行实际的处理, 比如 BytemArrayOutputStream -> OutputStream -> file
String -> ByteArrayInputStream(加工, 比如转换成大写字母) -> ByteArrayOutputStream -> byte[] array -> dest file 的例子:
package com.pratice.java300; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class MyMemoryCopy { public static void main(String[] args) { copyMemoryToFile("asdfxxxjjjgggqqq111", "xxx.txt"); } public static void copyMemoryToFile(String src, String dest) { try(ByteArrayInputStream bais = new ByteArrayInputStream(src.getBytes()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest)) ){ // 1.读取缓冲区的内容, 转换成大写字母 int ch = -1; byte[] out; while ((ch = bais.read()) != -1) { int upperCh = Character.toUpperCase((char)ch); baos.write(upperCh); } baos.flush(); // 2. 将缓冲区的文件输出为字节数组 out = baos.toByteArray(); // 3. 将字节数组写出到文件 bos.write(out); }catch(IOException e) { e.printStackTrace(); } } }
字节流 转字符流 (文件copy)
InputStreamReader : 读取字节流并帮助转换成字符流
OutputStreamWriter: 读取的是字符流并帮助转换成字节流
package com.pratice.java300; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; public class MyByte2Char { public static void main(String[] args) { byte2Char(); } public static void byte2Char() { try( // 从字节到字符 BufferedReader reader = new BufferedReader( new InputStreamReader( new URL("http://www.baidu.com").openStream(), "UTF-8")); // 从字符到字节 BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("baidu2.html"), "UTF-8"));){ String msg = null; while ((msg = reader.readLine()) != null) { writer.write(msg); writer.newLine(); } writer.flush(); }catch(IOException e) { e.printStackTrace(); } } }
数据流处理(保留了数据类型)
DataInputStream & DataOutputStream
处理的方式与下边的对象流一样. 在类似 socket 编程, 等需要传递时, 很常用.
注意, 进入数据流的顺序, 必须和出数据流的顺序一致.
所以, 你可以这么写:
String msg = dis.readWTF(); //这也不是把所有在流里的的 string 类型数据都读取出来, 而是通过顺序(进入数据流流), 顺序到这是String类型的.
int salary = dis.readInt(); // 这里的 dis 就是数据流, readInt() 并不是把所有的 int 型的数据都读取出来, 而是根据顺序的.
对象流(序列化 & 反序列化)
(后) ObjectInputStream : 将字节流转化为对象 (反序列化), 在你想要反序列化之前, 必须先使用 ObjectOutputStream 把对象序列化成字节流
(先) ObjectOutputStream : 将对象转换为 字节流(序列化)不是所有的对象都可以序列化, 必须实现一个接口 Serializable
对象 -> ObjectOutputStream 封装成字节流 -> ObjectInputStream -> 对象
package com.pratice.java300; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.sql.Date; public class MyObjectCopy { public static void main(String[] args) throws ClassNotFoundException { try( ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream dos = new ObjectOutputStream(baos); ){ dos.writeObject("asdf"); Employee employee = new Employee("张三", 10000); dos.writeObject(employee); dos.flush(); byte[] datas = baos.toByteArray(); ObjectInputStream dis = new ObjectInputStream(new ByteArrayInputStream(datas)); // 调用顺序与写入一样 Object msg = dis.readObject(); Object emp = dis.readObject(); if (msg instanceof String) { String msgObj = (String)msg; System.out.println(msgObj); } if (emp instanceof Employee) { Employee empObj = (Employee)emp; System.out.println(empObj); } }catch(IOException e) { e.printStackTrace(); } } } // javabean, 用来封装数据 class Employee implements Serializable{ private String name; private double salary; public Employee() { } public Employee(String name, double salary) { super(); this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Employee [name=" + name + ", salary=" + salary + "]"; } }
commonsIO 使用方法
遍历文件夹等, 很多可以直接使用.
工作中更多的使用这种成品工具, 像类似上边的自己实现, 不是很多机会.