一、概述
- IO流流动的是数据 --- 用于传输数据的API。
- InputStream\OutputStream --- 输入输出流
- 根据流的传输方向分类 :
- 当数据从外部流入程序时 : 输入流
- 当数据从程序流向外部时 : 输出流
- 根据流的传输形式分类:
- 字节流
- 字符流
- 不同形式交汇,得到四种基本操作流的类 , 四个基本流都是抽象类
输入流 输出流 字符流 Reader Writer 字节流 InputStream OutputStream
- 数据的来源: 硬盘、网络、内存、输入设备
- 字符输入流示例:
public class FileWriterDemo1 { public static void main(String[] args) throws Exception { // 无论这个文件是否存在,都会创建一个新的文件 ,不存在则创建,存在则覆盖 FileWriter writer = new FileWriter("E:\\a.txt"); // 写出数据 // java在底层对字符流设计了一个缓冲区,数据并不是直接写到目的地而是先写到了缓冲区中 // 等缓冲区满了之后才会将缓冲区中的数据一次性的放到目的地中。 // 由于缓冲区没有满而代码已经结束,所以数据就死在了缓冲区中 writer.write("def"); // 冲刷缓冲区 // writer.flush(); // 关闭流对象 // 流在关闭之前会自动的冲刷缓冲区,以防有数据死在缓冲区中 writer.close(); // 流在关闭之后依然存在,依然在占用内存 writer = null; System.out.println(writer); } }
- 字符输出流示例:
public class FileReaderDemo2 { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("E:\\a.txt"); // 创建一个字符数组作为缓冲区 char[] cs = new char[5]; // 定义一个变量来记录每次读取到字符个数 int len = -1; // 读取数据,将数据读取到字符数组中 while ((len = reader.read(cs)) != -1) { System.out.println(new String(cs, 0, len)); } // 关流 reader.close(); } }
- 字节输入流示例:
public class FileInputStreamDemo { public static void main(String[] args) throws Exception { FileInputStream fin = new FileInputStream("E:\\a.txt"); // 创建一个字节数组作为缓冲区 byte[] bs = new byte[3]; // 定义一个变量来记录每次读取的字节个数 int len = -1; while ((len = fin.read(bs)) != -1) { System.out.println(new String(bs, 0, len)); } fin.close(); } }
- 字节输出流示例:
public class FileOutputStreamDemo { public static void main(String[] args) throws Exception { FileOutputStream writer = new FileOutputStream("E:\\c.txt"); // 没有缓冲区 writer.write("abc".getBytes()); // 关流 writer.close(); } }
二、流的异常处理
- 第一步:流对象外置定义 内置初始化
- 第二步:防止流对象关闭时出现空指针异常 ,关闭前 对流对象判空
- 第三步:如果关流失败,则强制释放 ;如果关流成功,则释放流对象 ,释放内存
- 第四步:防止关流失败 ,在关流之前手动冲刷缓冲区
- 示例:
package cn.tedu.io.file; import java.io.FileWriter; import java.io.IOException; public class FileWriterDemo2 { public static void main(String[] args) { // 流对象要外置定义,在外置定义的时候需要把这个流对象置为null FileWriter writer = null; try { // 内置初始化 writer = new FileWriter("E:\\b.txt"); writer.write("abcdefg"); // 为了防止关流失败导致一部分数据的丢失,因此需要提前进行flush来保证数据的完整性 writer.flush(); } catch (Exception e) { e.printStackTrace(); } finally { // 需要判断流对象是否初始化成功 if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } finally { // 如果关流失败则强制回收流对象以释放文件 // 如果关流成功则用于释放这个流对象占用的内存 writer = null; } } } } }
- 练习: 剪切文件
public class CutFileDemo { public static void main(String[] args) throws Exception { // 创建一个file对象指向源文件 File oldFile = new File("E:\\a.txt"); // 创建一个输入流指向源文件 FileReader reader = new FileReader(oldFile); // 创建一个输出流来指向新文件 FileWriter writer = new FileWriter("D:\\a.txt"); // 创建一个字符数组作为缓冲区 char[] cs = new char[10]; // 定义一个变量记录每次读取到字符个数 int len = -1; // 读取数据 while ((len = reader.read(cs)) != -1) { // 将读取到数据写出 writer.write(cs, 0, len); } // 关流 reader.close(); writer.close(); // 删除源文件 oldFile.delete(); } }
三、缓冲流
- BufferedReader :从字符输入流中读取数据 , 提供一个缓冲区 , 允许按行读取
- BufferWriter : newLine() 产生新的一行。
- 字符输入缓冲流示例:
public class BufferedReaderDemo { public static void main(String[] args) throws Exception { // 实际上读取数据的流是FileReader, BufferedReader的作用是为这个流提供了一个缓冲区 BufferedReader reader = new BufferedReader(new FileReader("E:\\a.txt")); // 按行读取数据 String line = null; while((line = reader.readLine()) != null){ System.out.println(line); } // 关流---从里向外依次关闭 // Stream Already closed. reader.close(); } }
四、字节流
- 可以用字节流来读取任意文件 ,如: 视频 、音频
五、转换流
- 将字节转换为字符示例:
public class InputStreamReaderDemo { public static void main(String[] args) throws Exception { // 实际上读取数据的FileInputStream,转换流将字节转化为字符 InputStreamReader ir = new InputStreamReader(new FileInputStream("E:\\d.txt"), "utf-8"); // 数据是以字符形式来返回的 char[] cs = new char[4]; int len = -1; while ((len = ir.read(cs)) != -1) { System.out.println(new String(cs, 0, len)); } ir.close(); } }
- 将字符转换为字节示例:
public class OutputStreamWriterDemo { public static void main(String[] args) throws Exception { // 在底层实际上传输数据的是FileOutputStream,转换流提供的操作是将字符转化为字节 // 当没有指定转换编码的时候,默认使用的是系统平台码 OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("E:\\d.txt"), "utf-8"); // 写出数据 ow.write("转换"); // 关流 ow.close(); } }
- 练习: 改变文件的编码
public class ChangeEncodeExer { public static void main(String[] args) throws Exception { // 创建一个file对象指向源文件 File file = new File("F:\\java基础增强.txt"); // 创建一个file对象指向临时文件 File temp = new File("F:\\temp.txt"); // 创建一个输入流来读取源文件 BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8")); // 创建一个输出流将读取的内容写到临时文件中 // BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(temp))); // 定义一个变量来记录读取的每行数据 String msg = null; // 读取数据 while ((msg = br.readLine()) != null) { // 将读取到的数据写出 bw.write(msg); // 换行 bw.newLine(); } // 关流 br.close(); bw.close(); // 删除源文件 file.delete(); // 重命名新文件 temp.renameTo(file); } }
六、系统流\标准流
- 系统流示例:
public class SystemDemo { public static void main(String[] args) throws Exception { // 系统流都是字节流 int i = System.in.read(); // 在使用的时候没有任何差别,只是在输出结果上有颜色的差别 // 如果是正常的结果使用out来输出打印,如果是错误的结果会使用err来输出打印 System.out.println(i); System.err.println(i); System.out.println(new char[]{'a','d'}); System.out.println(new int[]{'a','d'}); } }
- 练习: 从控制台读取内容后输出
public class GetLineExer { public static void main(String[] args) throws Exception { // 从控制台获取---System.in // 获取一行数据---BufferedReader // System.in是一个字节,BufferedReader需要一个字符流---字节转化成字符---InputStreamReader BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println(br.readLine()); br.close(); // br = new BufferedReader(new InputStreamReader(System.in)); // System.out.println(br.readLine()); // br.close(); } }
七、打印流
八、 合并流
- 示例:
public class SequenceInputStreamDemo { public static void main(String[] args) throws Exception { // 创建输入流分别对应的文件 FileInputStream in1 = new FileInputStream("E:\\a.txt"); FileInputStream in2 = new FileInputStream("E:\\c.txt"); FileInputStream in3 = new FileInputStream("E:\\d.txt"); // 创建一个Vector集合 Vector<InputStream> vec = new Vector<InputStream>(); vec.add(in1); vec.add(in2); vec.add(in3); // 转化为一个Enumeration Enumeration<InputStream> e = vec.elements(); // 创建合并流对象 SequenceInputStream sis = new SequenceInputStream(e); // 读取数据 byte[] bs = new byte[10]; int len = -1; // 在合并的时候没有办法控制文件的编码 while ((len = sis.read(bs)) != -1) { System.out.println(new String(bs, 0, len)); } // 关流 sis.close(); } }
九、序列化流\反序列化流
- 示例:
public class Person implements Serializable { // 版本号---用版本号来标识一个类。 // 当一个对象反序列化回来的时候,会自动的比较对象中的版本号和当前类中的版本号是否一致、 // 如果一致Java才认为这个对象是本类的对象,才允许反序列化 // 如果没有手动指定版本号,JVM在编译的时候会根据当前类中的方法和属性自动计算一个版本号 // private static final long serialVersionUID = 329L; private static final long serialVersionUID = 6920415629894220824L; private String name; private int age; private char gender; private double heigh; // 被transient修饰的属性不能被序列化 private transient double weight; public double getHeigh() { return heigh; } public void setHeigh(double heigh) { this.heigh = heigh; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } // public static boolean alive; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class SerialDemo { public static void main(String[] args) throws Exception { // 准备要序列化的对象 Person p = new Person(); p.setName("酸菜鱼"); p.setAge(16); p.setWeight(190); // p.alive = true; // 创建一个用于序列化的流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\p.data")); // 将对象序列化出去 oos.writeObject(p); // 关流 oos.close(); } } public class DeserialDemo { public static void main(String[] args) throws Exception { // 创建反序列化流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\p.data")); // 反序列化对象 Person p = (Person) ois.readObject(); // 关流 ois.close(); System.out.println(p.getName()); System.out.println(p.getAge()); // 如果一个属性没有序列化出去,那么反序列化回来的时候会给这个属性一个默认值 System.out.println(p.getWeight()); } }
- 序列化加密示例:
public class 加密例子 { Key key; public void serial(Person p) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, IOException { // 需要找制作钥匙的对象 // 在此的规则指的加密算法---对称加密,非对称加密 KeyGenerator generator = KeyGenerator.getInstance("DESede"); // 产生钥匙 key = generator.generateKey(); // 产生锁 Cipher cipher = Cipher.getInstance("DESede"); // 将锁和钥匙配对 // 第一个参数表示钥匙和锁的配对模式 cipher.init(Cipher.ENCRYPT_MODE, key); // 找盒子 SealedObject so = new SealedObject(p, cipher); // 将盒子序列化出去 ObjectOutputStream ois = new ObjectOutputStream(new FileOutputStream("p.data")); ois.writeObject(so); ois.close(); } public Person deSerial() throws FileNotFoundException, IOException, ClassNotFoundException, InvalidKeyException, NoSuchAlgorithmException{ // 创建反序列化流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("p.data")); // 反序列化盒子 SealedObject so = (SealedObject) ois.readObject(); // 关流 ois.close(); // 将对象从盒子中取出 return (Person) so.getObject(key); } public static void main(String[] args) throws Exception { 加密例子 demo = new 加密例子(); Person p = new Person(); p.setName("张三疯"); p.setAge(500); p.setGender('男'); demo.serial(p); } }
十、 Properties
- 示例:
public class PropertiesDemo1 { public static void main(String[] args) throws Exception { // 创建properties对象 Properties prop = new Properties(); // 添加键值对 prop.setProperty("key", "value"); prop.setProperty("second", "value"); // 持久化这个映射---必须存储到properties文件中 // 第二个参数表示给properties文件添加一个注释---用于解释当前properties文件的作用 prop.store(new FileOutputStream("c.properties"), "this is a demo ."); } }
public class PropertiesDemo2 { public static void main(String[] args) throws Exception { Properties prop = new Properties(); // 反序列化 prop.load(new FileInputStream("c.properties")); System.out.println(prop.getProperty("key")); System.out.println(prop.getProperty("second","ok")); // 如果键不存在,则返回一个null // 如果键不存在,则返回指定的值---第二个参数 System.out.println(prop.getProperty("键", "non")); } }
十一、 枚举
- 示例1:
public class EnumDemo { @SuppressWarnings("unused") public static void main(String[] args) { Season s = Season.Autumn; } } class Season { // 不允许在类外随意创建对象 private Season() { } static final Season Spring = new Season(); static final Season Summer = new Season(); static final Season Autumn = new Season(); static final Season Winter = new Season(); }
- 示例2:
public class EnumDemo2 { public static void main(String[] args) { Level l = Level.B; // l.print(); switch (l) { case A: System.out.println("ok"); break; case B: System.out.println("B~~~"); break; default: break; } } } enum Level { // 默认构造函数是私有的而且只能是私有的 // 每个枚举常量之间用 , 隔开,最后一个枚举常量之后最好加上 ; 表示结束 // public static final Level A = new Level(); // 枚举常量必须定义在枚举类的首行 A(90) { @Override public void print() { System.out.println("优秀"); } }, B(80) { @Override public void print() { System.out.println("良好"); } }, C(70) { @Override public void print() { System.out.println("中等"); } }, D(60) { @Override public void print() { System.out.println("及格"); } }, E(0) { @Override public void print() { System.out.println("不及格"); } }; private Level(double score) { this.score = score; } private Level() { } private double score; public static double average; public double getScore() { return score; } public static void set(double sum) { System.out.println(sum / average); } public void setScore(double score) { this.score = score; } public abstract void print(); }