文件管理和输入输出流

文件概述

数据存储方案

数据临时性存储方案:(计算机内存的中存储的数据会在计算机断电后清空)

变量、数组、对象、集合

数据 "持久性" 储存方案:(计算机硬盘中存储的数据在正常情况下不会消失)

  • 文件:存储在某种长期储存设备(磁盘、光盘、磁带等)上的一段数据流
    • 文件储存的特点:所存信息可以长期、多次使用,不会因为断电而消失

文件管理File类

Java提供的,用于操作文件/文件夹的API

构造方法

  • File(String path) 通过传入的 文件/文件夹路径(字符串) 构建一个 File 对象

注意:在使用路径分隔符 `\` 时,小心被 Java 识别为转义字符,要使用 '\\' 转义

// 构建File对象时,两种路径的写法
File file1 = new File("d:\\Develop");
File file2 = new File("d:/Develop");
  • File(String parent, String child) 通过文件/文件夹的父路径 + 子路径来构建一个 File 对象
File file = new File("d:\\", "Develop");
  • File(File parent, String child) 通过文件/文件夹的父 File 对象 + 子路径来构建一个 File 对象
File file1 = new File("d:");
File file2 = new File(file, "Develop");

常用方法

  • exists() : boolean 判断文件/文件夹是否存在
  • isFile() : boolean 判断是否是文件
  • isDirectory() : boolean 判断是否是文件夹
  • getName() : String 获取文件/文件夹的名字
  • length() : long 获取文件的大小(单位:字节)
  • createNewFile() : boolean 创建文件
  • delete() : boolean 删除文件/文件夹(只能删除空文件夹,且不进入回收站)
  • list() : String[] 获取指定文件夹下的所有内容列表(文件/文件夹)
  • listFiles() : File[] 获取指定文件夹下的所有内容的 File 对象列表(文件/文件夹)
  • listFiles(FileFilter fileFilter) : File[] 根据 文件过滤器 来获取指定文件夹下的所有内容的 File 对象列表

           FileFilter 文件过滤器接口:(返回值为 true :保留 false: 舍弃)

                   实现方法一:定义个匿名内部类,重写accept方法

                   实现方法二:创建一个接口实现类,重写accept方法

输入输出流(IO流)概述

流:流动的水、流动的电、流动的车...

数据流:可以流动的数据

  • 根据流动方法分类:(流动的方向时根据程序来决定的)
    • 输入流:从数据源流动到程序(读取)
    • 输出流:从程序流动到目的地(写入)
  • 根据处理的单位分类:
    • 字节流:单位字节,byte
      • 字节流是最基础的一种处理单位
      • 用于文件、图片复制等处理(用记事本打开后是看不懂的乱码)
    • 字符流:单位字符,char
      • 字符流是基于字节流产生的
      • 用于文本文档等需要进行内容操作的处理(用记事本打开后是看的懂的字)

输入输出流大体分类:

字节输入流、字节输出流、字符输入流、字符输出流

字节流

字节输入流(fileInputStream)

构造方法:(没有目标文件会报错

  • FileInputStream(File file)
  • FileInputStream(String name) 底层就是用第一种构造

常用方法:

  • read() : int 读取一个字节的内容(没有下一个字节,返回 -1)
// 循环读取示例
int b = 0;
while ((b = fis.read()) != -1) {
    System.out.print((char) b);
}
  • read(byte[] buffer) : int 读取一个字节数组的内容,返回读取了多少个字节到字节数组中,返回 -1 表示读取结束。
  • close() : void 关流/释放资源(开启流之后,一定要关流!)

字节输出流(FileOutputSream)

构造方法 :(如果目标文件不存在,会自动创建)

  • FileOutputStream(String name) 根据目的地路径,构建一个输出流
  • FileOutputStream(String name, boolean append) 根据目的地路径,来构建一个输出流,append 代表是否是追加数据(true:追加 false:覆盖)
  • FileOutputStream(File file) 根据目的File对象,构建一个输出流
  • FileOutputStream(File file, boolean append) 根据目的File对象,构建一个输出流

常用方法:

  • write(int b) : void 写入一个字节数据
  • write(byte[] b) : void 写入一个字节数组的数据
  • write(byte[] b, int off, int len) : void 写入一个字节数组指定范围的数据 (off:起始索引 len:写入长度)
  • close() : void 关流

 

关流

在使用流相关的 API 时,操作结束后要关流!

Java7 - :正确的关流方式

一般的,为了保证流资源能够正确关闭,将关闭流的方法调用放在 finally 中

FileInputStream fis = null;
try {
    // 指定数据源
    fis = new FileInputStream("d:/a.txt");

    // 读取数据
    byte[] buffer = new byte[6];
    fis.read(buffer);
    for (byte b : buffer) {
        System.out.print((char) b);
    }
} finally {
    // 关流
    if (fis != null) {
        fis.close();
    }
}

Java7 + :自动资源管理 (实现了AutoCloseable接口的类不再需要手动资源释放,java会自动调用类的close方法)

try-with-resource

try (FileInputStream fis = new FileInputStream("d:/a.txt")) {
    // 读取数据
    byte[] buffer = new byte[6];
    fis.read(buffer);
    for (byte b : buffer) {
        System.out.print((char) b);
    }
} catch (Exception e) {
    e.printStackTrace();
}

 

字节流实现文件的复制

需求:将 d 盘的 a.txt 复制到 e 盘

// 指定数据源和输出目的地(创建输入流和输出流)
try (FileInputStream fis = new FileInputStream("d:/a.txt");
     FileOutputStream fos = new FileOutputStream("e:/a.txt")) {

    // 边读边写
    // 读取d盘a.txt内容
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = fis.read(buffer)) != -1) {
        // 将读取到的内容写入e盘a.txt
        fos.write(buffer, 0, len);
    }

    System.out.println("复制成功!");
} catch (Exception e) {
    e.printStackTrace();
}

字符流

字符输入流(FileReader

构造方法:

  • FileReader(String fileName)
  • FileReader(File file)

常用方法:

  • read() : int 读取一个字符
  • read(char[] cbuf) : int 读取一个字符数组的内容,返回的是读取了多少个字符到字符数组中,返回 -1 代表读取结束
  • close() : void 关流

字节输出流(FileWriter

构造方法:

  • FileWriter(String fileName)
  • FileWriter(String fileName, boolean append)
  • FileWriter(File file)
  • FileWriter(File file, boolean append)

常用方法:

  • write(int c) : void 输出一个字符
  • write(char[] cbuf) : void 输出一个字符数组
  • write(char[] cbuf, int off, int len) : void 输出一个字符数组的一部分
  • write(String str) : void 输出一个字符串
  • write(String str, int off, int len) : void 输出一个字符串的一部分
  • close() : void 关流
  • flush() : void 刷新缓冲区

高效字符流

高效字符输入流(BufferedReader

构造方法:

  • BufferedReader(Reader in)

常用方法:

  • readLine() : String 读取一行

高效字符输出流(BufferedWriter

构造方法:

  • BufferedWriter(Writer out)

常用方法:

  • newLine() : void 文本换行

高效字节流的其他方法与字符输入流共有。

读取各种类型数据(了解)

DataInputStream

DataOutputStream

构造方法:

  • DataInputStream(InputStream in)
  • DataOutputStream(OutputStream out)

常用方法:

  • readUTF() : String
  • readInt() : int
  • readDouble() : double
  • readChar() : char
  • readBoolean() : boolean
  • writeUTF(String) : void
  • writeInt(int) : void
  • writeDouble(double) : void
  • writeChar(char) : void
  • writeBoolean(boolean) : void
  • close() : void

 

序列化与对象流

ObjectInputStream:反序列化

构造方法:

  • ObjectInputStream(InputStream in)

常用方法:

  • readObject() : Object 读取对象

 

ObjectOutputStream :序列化

构造方法:

  • ObjectOutputStream(OutputStream out)

常用方法:

  • writeObject(Object obj) : void 写入对象

注意: 在输出对象时,该对象所属的 类 必须实现序列化接口

public class 类名 implements Serializable {
    
}

序列化和反序列化

阿里巴巴开发手册要求:

【强制】 序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;

如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。

说明: 注意 serialVersionUID 不一致会抛出序列化运行时异常。

异常详情:

java.io.InvalidClassException: 包名.实体类名; local class incompatible: stream classdesc serialVersionUID = 6956675782234049705, local class serialVersionUID = -2472659678273126616
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
	at 包名.测试类名.main(包名.java:xx)

serialVersionUID:类在实现序列化接口后,如果没有指定serialVersionUID,系统会根据类的信息自动生成一个serialVersionUID

注意:系统自动生成的serialVersionUID会根据类的信息改变(新增、删除属性)而改变,无法进行兼容性的升级。

问题:当类的内容改变时(即serialVersionUID发生改变后),原有序列化的内容无法反序列化回来

解决方案:在序列化类中手动添加一个 serialVersionUID ,这样是否允许兼容性升级,可以由为我们自己来控制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值