> 文档中心 > 【Java-IO】Scanner、格式化输出、数据流(Data Streams)、对象流(Object Streams)、序列化(Serialization)、Files工具类

【Java-IO】Scanner、格式化输出、数据流(Data Streams)、对象流(Object Streams)、序列化(Serialization)、Files工具类


八、IO

文章目录

  • 八、IO
    • 12_Scanner
    • 13_格式化输出
      • `PrintStream`
      • `PrintWriter`
    • 14_数据流(Data Streams)
    • 15_对象流(Object Streams)、序列化(Serialization)
      • 对象的序列化和反序列化
      • serialVersionUID
      • transient
      • 序列化与反序列化
      • `ObjectOutputStream` – 序列化
      • `ObjectInputStream` – 反序列化
    • 16_Files工具类

12_Scanner

java.util.Scanner 是一个可以使用正则表达式解析基本类型字符串的简单文本扫描器

  • 它默认利用空白空格\制表符\行终止符)作为分隔符将输入分隔成多个 token
Scanner(InputStream source)Scanner(Readable source)Scanner(File source)Scanner(String source)
Scanner sc = new Scanner("jack rose kate");while(sc.hasNext()){System.out.println(sc.next());}sc.close();
jackrosekate
Scanner sc = new Scanner("jack 666 888 ak47");System.out.println(sc.next()); // jackSystem.out.println(sc.nextInt()); // 666System.out.println(sc.nextDouble()); // 888.0// 利用正则表达式分隔文本System.out.println(sc.next("[a-z]{2}\\d{2}")); // ak47sc.close();
jack666888ak47
  • Scanner.useDelimiter 方法可以自定义分隔符
Scannersc = new Scanner("aa 1 bb 22 cc33dd");sc.useDelimiter("\\s*\\d+\\s*");while(sc.hasNext()){System.out.println(sc.next());}// aa bb cc ddsc.close();
aabbccdd
Scanner sc = new Scanner("aa11bb22cc");sc.useDelimiter(""); // 任意字符都被分隔while(sc.hasNext()) {System.out.println(sc.next());} // a a 1 1 b b 2 2 c csc.close();
aa11bb22cc
  • Scanner - 标准输入流
Scannersc = new Scanner(System.in);System.out.print("请输入第1个整数:");int n1 = sc.nextInt();System.out.print("请输入第2个整数:");int n2 = sc.nextInt();System.out.format("%d + %d = %d%n", n1, n2, n1 + n2);sc.close();
请输入第1个整数:6请输入第2个整数:86 + 8 = 14

Scanner – “价值几百万”的 AI 代码

Scanner sc = new Scanner(System.in);while(sc.hasNextLine()){String str = sc.nextLine();str = str.replace("你", "朕");str = str.replace("吗", "");str = str.replace("么", "");str = str.replace("?", "!");str = str.replace("?", "!");System.out.println("\t" + str);}sc.close();

13_格式化输出

有 2 个类可以实现格式化输出

  • PrintStream
  • PrintWriter

它们有 3 个常用方法:printprintlnformat

printwrite 的区别

  • write(97) 写入的是字符 'a'
  • print(97) 写入的是字符串 "97"

在这里插入图片描述

PrintStream

System.outSystem.errPrintStream 类型的实例

  • 属于标准输出流(Standard Ouput Stream)
  • 比如输出到屏幕、控制台(Console)

PrintStream 是字节流,但它内部利用字符流对象来模拟字符流的许多功能

PrintWriter

平时若要创建格式化的输出流,一般使用 PrintWriter,它是字符流

String name = "Jack";int age = 20;PrintWriter writer = new PrintWriter("F:/1.txt");writer.format("My name is %s,age is %d", name, age);writer.close();

可以通过构造方法设置 PrintWriter.autoflush 为 true

  • 那么 printlnprintfformat 方法内部就会自动调用 flush 方法
PrintWriter writer = new PrintWriter(new FileOutputStream(new File("F:/1.txt")), true);

14_数据流(Data Streams)

有 2 个数据流:DataInputStreamDataOutputStream,支持基本类型字符串类型的 I / O 操作

  • DataOutputStream 将数据写到文件当中
int age = 20; int money = 3000; doubleheight = 1.75;String name = "Jack";DataOutputStream dos = new DataOutputStream(new FileOutputStream("F:/66.txt"));dos.writeInt(age);dos.writeInt(money);dos.writeDouble(height);dos.writeUTF(name);dos.close();
  • DataInputStream 将数据从文件当中读取数据
DataInputStream dis = new DataInputStream(new FileInputStream("F:/66.txt"));System.out.println(dis.readInt());System.out.println(dis.readInt());System.out.println(dis.readDouble());System.out.println(dis.readUTF());dis.close();

在这里插入图片描述

15_对象流(Object Streams)、序列化(Serialization)

有 2 个对象流:ObjectInputStreamObjectOutputStream,支持引用类型I / O 操作

只有实现了 java.io.Serializable 接口的类才能使用对象流进行 I / O 操作

  • 否则会抛出 java.io.NotSerializableException 异常

Serializable 是一个标记接口(Maker Interface),不要求实现任何方法

对象的序列化和反序列化

序列化(Serialization)

  • 将对象转换为可以存储或传输的数据
  • 利用 ObjectOutputStream 可以实现对象的序列化

反序列化(Deserialization )

  • 从序列化后的数据中恢复出对象
  • 利用 ObjectInputStream 可以实现对象的反序列化

若将对象比作是一座冰雕

  • 序列化:将冰雕融化成水
  • 反序列化:将融化后的水恢复成冰雕

serialVersionUID

每一个可序列化类都有一个 serialVersionUID,相当于类的版本号

  • 默认情况下会根据类的详细信息计算出 serialVersionUID 的值,根据编译器实现的不同可能千差万别
  • 一旦类的信息发生修改,serialVersionUID 的值就会发生变化

如果序列化、反序列时的 serialVersionUID 不一致

  • 会认定为序列化、反序列时的类不兼容,会抛出 java.io.InvalidClassException 异常

强烈建议每一个可序列化类都自定义 serialVersionUID,不要使用它的默认值

  • 必须是 static final long
  • 建议声明为 private
  • 如果没有自定义 serialVersionUID,编译器会发出 “serial” 警告

transient

transient 修饰的实例变量不会被序列化

public class Dog implements Serializable {private transient int age; // age不会被序列化private String name;public Dog(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Dog [age=" + age + ", name=" + name + "]";}}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("F:/d.txt"));oos.writeObject(new Dog(5, "Larry"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:/d.txt"));System.out.println(ois.readObject()); // Dog [age=0, name=Larry],age没有被序列化ois.close();
Dog [age=0, name=Larry]

序列化与反序列化

import java.io.Serializable;public class Car implements Serializable {private static final long serialVersionUID = 1L;private double price;private String band;public Car(double price, String band) {this.price = price;this.band = band;}@Overridepublic String toString() {return "Car [price=" + price + ", band=" + band + "]";}}
import java.io.Serializable;public class Book implements Serializable {private static final long serialVersionUID = 1L;private double price;private String name;public Book(double price, String name) {super();this.price = price;this.name = name;}@Overridepublic String toString() {return "Book [price=" + price + ", name=" + name + "]";}}
import java.io.Serializable;import java.util.ArrayList;import java.util.List;public class Person implements Serializable {private static final long serialVersionUID = 1L;private int age;private String name;private Car car;private List<Book> books = new ArrayList<>();public Person(int age, String name) {this.age = age;this.name = name;}public List<Book> getBooks(){ return books; }public void setCar(Car car) { this.car = car; }@Overridepublic String toString() {return "Person [age=" + age + ", name=" + name + ", car=" + car + ", books=" + books + "]";}}

ObjectOutputStream – 序列化

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("F:/p.txt"));Person p = new Person(20, "Jack");p.setCar(new Car(305.6, "Bently"));p.getBooks().add(new Book(19.9, "Java"));p.getBooks().add(new Book(38.8, "C++"));oos.writeObject(p);Car c = new Car(107.8, "BMW");oos.writeObject(c);oos.close();

ObjectInputStream – 反序列化

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:/p.txt"));Person p = (Person)ois.readObject();System.out.println(p);Car c = (Car)ois.readObject();System.out.println(c);ois.close();
Person [age=20, name=Jack, car=null, books=[Book [price=19.9, name=Java], Book [price=38.8, name=C++]]]Car [price=107.8, band=BMW]

16_Files工具类

import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileReader;import java.io.IOException;import java.io.OutputStream;import java.io.Reader;import java.util.function.Consumer;public class Files {/** * 搜索目录下的所有文件 * @param dir 目录 * @param operation 执行的操作 */public static void search(File dir, Consumer<File> operation){if(dir == null || operation == null) return;// 目录不存在 或者 传入的是文件, 不执行操作if(!dir.exists() || dir.isFile()) return; File[] subfiles = dir.listFiles();for (File sf : subfiles) {operation.accept(sf);if(sf.isFile()) continue; // 如果是文件,跳过,进行后面的搜索search(sf, operation); // 如果是文件夹, 递归搜索该文件夹}}/** * 删除文件夹 * @param file */public static void delete(File file){// 传入null 或者  文件夹不存在, 不执行操作if(file == null || !file.exists()) return;clean(file);file.delete();}/** * 清空文件夹中文件 * @param dir */public static void clean(File dir){// 如果文件夹不存在 或者 传入的是文件, 不执行操作if(dir == null || !dir.exists() || dir.isFile()) return;File[] subfiles = dir.listFiles();for (File sf : subfiles) {delete(sf);}}/** * 剪切文件或文件夹到目标路径 */public static void move(File src, File dest){if(src == null || dest == null) return;// 如果源File不存在 或者 目标File 已经存在, 不执行操作if(!src.exists() || dest.exists()) return;mkparents(dest);src.renameTo(dest);}/** * 将内存中的数据写入文件 */public static void write(byte[] bytes, File file){if(bytes == null || file ==null) return;if(file.exists()) return; // 如果文件已经存在,直接结束,不覆盖mkparents(file);try(FileOutputStream fos = new FileOutputStream(file)){fos.write(bytes);} catch (IOException e) {e.printStackTrace();}}/** * 将数据从文件读入到内存中 */public static byte[] read(File file){if(file == null || !file.exists()) return null;if(file.isDirectory()) return null; // 不读取文件夹try(FileInputStream fis = new FileInputStream(file)){byte[] bytes = new byte[(int)file.length()];fis.read(bytes);return bytes;} catch (IOException e) {e.printStackTrace();return null;}};/** * 复制(只限于文件) */public static void copy(File src, File dest){if(src == null || dest == null) return;if(!src.exists() || dest.exists()) return;if(src.isDirectory()) return; // 不拷贝文件夹mkparents(dest);try(FileInputStream fis = new FileInputStream(src);FileOutputStream fos = new FileOutputStream(dest);){byte[] bytes = new byte[8192];int len;while((len = fis.read(bytes)) != -1){fos.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}}/** * 练习 – 将文本文件的内容逐个字符打印出来 */public static void writeChar(File file){if(file == null || file.isDirectory()) return;try(FileReader reader = new FileReader(file)) {int c;while((c = reader.read()) != -1){System.out.print((char)c);Thread.sleep(100);}} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}/** * 练习 - 缓冲流逐行打印字符串 */public static void writeLine(File file){try(BufferedReader reader = new BufferedReader(new FileReader(file))){String line;while((line = reader.readLine()) != null){System.out.println(line);Thread.sleep(100);}} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}/** * 创建父路径 */private static void mkparents(File file){File parent = file.getParentFile();if(parent == null) return;parent.mkdirs();}}

古诗弟