java - day013 - 流, FileInputStream, BufferedInputStream,
- 流 Stream
- 把数据的读写,抽象成数据在管道中流动.
- 流是单向的
- 输入流, 只能用来读取数据
- 输出流, 只能用来输出数据
- 流只能顺序读写数据
- 流只能一次性从头到尾读写数据
- 流动过的数据,不能反复流动
- 重复读写数据,只能重新新建流
- InputStream/OutputStream
- 字节流的抽象父类
- 方法
- write(int b);
- write(byte[]);
- write(byte[] , start, length);
- flush();刷出缓存数据
- read();
- read(byte[] buff);批量读取,返回读取的数据数量
- available(); 剩余可读取的字节数量
- FileInputStream/FileOutputStream
- 直接插在文件上, 读写文件数据
- 创建对象
- new FileOutputStream(文件);
- 不管文件是否存在, 都会新建一个空文件
- 如果文件存在, 空文件会覆盖原文件
- new FileOutputStream(文件, true);
- 文件存在,追加数据
-
package day1302; import java.io.FileOutputStream; import java.io.IOException; public class Test1 { public static void main(String[] args) throws IOException { // 新建文件输出流 FileOutputStream outF = new FileOutputStream("/Users/dingzhijie/Desktop/file.txt"); outF.write(97); outF.write(98); outF.write(99); outF.write(356); byte[] a = {101,102,103,104,105,106,107,108,109,110}; outF.write(a); outF.write(a, 2, 4);
outF.close();
} }
package day1302; import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; public class Test2 { public static void main(String[] args) throws IOException { FileInputStream inputF; // 因为流只能读取一次数据, 所以需要重复创建 inputF = new FileInputStream("/Users/dingzhijie/Desktop/file.txt"); // 单字节读取 int b; while ((b = inputF.read()) != -1) { System.out.println(b); } inputF.close(); inputF = new FileInputStream("/Users/dingzhijie/Desktop/file.txt"); // 批量读取 int c; byte[] buff = new byte[5]; while ((c = inputF.read(buff)) != -1) { System.out.println(c+"\t"+Arrays.toString(buff)); } inputF.close(); } }
- 复制文件
-
package day1302; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Scanner; public class Test3 { public static void main(String[] args) { // 文件复制 System.out.println("源文件:"); String s1 = new Scanner(System.in).nextLine(); File from = new File(s1); if (!from.isFile()) { System.out.println("不是文件"); return; } System.out.println("目标文件"); String s2 = new Scanner(System.in).nextLine(); File to = new File(s2); if (to.isDirectory()) { System.out.println("不能是文件夹"); return; } try { copy(from,to); System.out.println("复制完成"); } catch (Exception e) { System.out.println("复制失败"); e.printStackTrace(); } } // 首先添加异常的抛出管道 private static void copy(File from, File to) throws Exception { /* * 在源文件上插入输入流, 输入数据到内存 * 在目标文件上插入输出流, 从内存输出数据到目标文件 * */ // 循环批量读取 // 然后向目标文件输出 FileInputStream in = new FileInputStream(from); FileOutputStream out = new FileOutputStream(to); byte[] buff = new byte[8192]; int n; while ((n = in.read(buff)) != -1) { out.write(buff, 0, n); } in.close(); out.close(); } }
- 高级流 . 操作流
- 与其他流相接, 提供特定的数据处理功能
- 对高级流的操作, 会对相接的流执行相同操作
- 关闭最后的高级流,会同样关闭相接的其他流
- BufferedInputStrwam/BufferedOutputStream
- 缓冲流
- 提供内存缓冲数组
- 用来提高单字节的读写效率
- 作用
- 帮助单字节读取批量读写操作
- 提高单字节读取效率,对批量读取效率提高无效
-
package day1303; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class Test1 { public static void main(String[] args) throws IOException { /* * */ String path = "/Users/dingzhijie/Desktop/file3.txt"; BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(path)); bout.write(97); bout.write(98); bout.write(99); // 写入数据是,先写入 BufferedOutputStream 内部的缓存数组中 // 满 8192 (8k) 数量, 会自动触发批量写入操作,不满不会触发 // 此时 三个数据 不会自动触发写入操作 // 需要手动刷出缓存 bout.flush(); /* * 高级流的 close 方法 * 会先执行 flush(); * 然后关闭相接的流 */ bout.close(); } }
-
使用 BufferedInputStream / BufferedOutputStream 文件复制
-
package day1302; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Scanner; public class Test4 { public static void main(String[] args) { // 文件复制 System.out.println("源文件:"); String s1 = new Scanner(System.in).nextLine(); File from = new File(s1); if (!from.isFile()) { System.out.println("不是文件"); return; } System.out.println("目标文件"); String s2 = new Scanner(System.in).nextLine(); File to = new File(s2); if (to.isDirectory()) { System.out.println("不能是文件夹"); return; } try { copy(from,to); System.out.println("复制完成"); } catch (Exception e) { System.out.println("复制失败"); e.printStackTrace(); } } // 首先添加异常的抛出管道 private static void copy(File from, File to) throws Exception { /* * 在源文件上插入输入流, 输入数据到内存 input * 在目标文件上插入输出流, 从内存输出数据到目标文件 output * */ // 使用 BufferedInputStream / BufferedOutputStream 单字节读写 FileInputStream in = new FileInputStream(from); BufferedInputStream bin = new BufferedInputStream(in); FileOutputStream out = new FileOutputStream(to); BufferedOutputStream bout = new BufferedOutputStream(out); int n; while ((n = bin.read()) != -1) { bout.write(n); } bin.close(); bout.close(); } }
- ObjectInputStream / ObjectOutputStream 对象序列化. 反序列化
- 序列化
- 对象的信息,按固定的格式,转成一串字节序列输出
- ObjectOutputStream 对象序列化
- writeObject(Object);
- 把对象序列化输出
-
package day1304; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Test1 { public static void main(String[] args) throws IOException { /* * * 把Student 对象序列化输出 , 保存到文件 * * ObjectOutputStream FileOutputStream * */ Student s1 = new Student(12, "张三", "男", 17); String path = "/Users/dingzhijie/Desktop/file4.txt"; FileOutputStream fos = new FileOutputStream(path); ObjectOutputStream ofos = new ObjectOutputStream(fos); ofos.writeObject(s1); ofos.close(); // 注意: 被序列化的对象的类 必须 实现 Serializable 接口 // Serializable 是一个空接口,不需要实现任何抽象方法 // 只是做一个标识,标识这个类的对象可以被序列化 } }
- ObjectInputStream
- readObject();
- 读取对象的序列化数据
- 反序列化恢复对象
-
package day1304; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Test2 { public static void main(String[] args) throws IOException, ClassNotFoundException { /* * 读取序列化数据 * 反序列化恢复学生对象 * 插入文件输入流 */ String path = "/Users/dingzhijie/Desktop/file4.txt"; FileInputStream fis = new FileInputStream(path); ObjectInputStream bfis = new ObjectInputStream(fis); Object s1 = bfis.readObject(); Student s = (Student) s1; System.out.println(s.toString()); bfis.close(); } }
- 不序列化的成员
- static ,属于类, 不随对象被序列化输出
- transient , 临时,
- 只在程序运行期间在内存中存在,不会随对象持久的保存
- 不序列化的成员反序列化时返回默认值
-
- 序列化版本号
- 旧版本的数据, 不允许恢复新版本的类型
- 如果自己不定义, 编译器编译时,会根据类的定义信息自动生成一个版本号
-
/** * 序列化版本号 */ private static final long serialVersionUID = 2018L;
- 如果类被编译过后, 版本号变化,反序列化以前的旧数据会报错,
- 可以手动修改以前数据的版本号,执行反序列化
没有那个时代犹如现在,知识的爆发和技术的进步如此的迅速,必须不断的学习才能紧跟时代的步伐 . (PS:资料来源比较复杂 ,如有侵权 , 删)