Java IO流(八)

Updated on in Java with 0 views and 0 comments

IO流

概述

  • IO:输入/输出(Input/Output)

  • :是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输

  • IO流就是用来处理设备间数据传输问题的

    • 常见的应用:文件复制、文件上传、文件下载
  • IO流分类

    • 按照数据的流向
      • 输入流:读数据
      • 输出流:写数据
    • 按照数据类型
      • 字节流:字节输入流、字节输出流
      • 字符流:字符输入流、字符输出流
  • 字节流

    字节流.png

  • 字符流

    字符流.png

File

概述

  • File:它是文件和目录路径名的抽象表示
  • 文件和目录是可以通过File封装成对象的
  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,该路径可以是存在的,也可以是不存在的。

File类的构造方法

方法名说明
File(String pathname)通过将给定的路径名字字符串转换为抽象路径名来创建新的File实例
File(String parent,String child)父路径名字符串子路径名字符串创建新的File实例
File(File parent,String child)父抽象路径名子路径名字符串创建新的File实例
  • 注意:路径的分隔符 ’\‘ 需通过添加转义字符 ’\‘ 表示,格式为 ’\\‘

File类创建功能

方法名说明
public booleancreateNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public booleanmkdir()创建由此抽象路径名命名的目录(创建单个目录
public booleanmkdirs()创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录(创建多个嵌套目录
  • 注意:系统要求目录文件不能重名。

File类删除功能

方法名说明
public booleandelete()删除由此抽象路径名表示的文件目录
  • 注意:
    • 若为抽象路径名指定的是路径字符串是相对路径,则默认目录是idea当前项目目录
    • 如果一个目录中有内容(目录,文件),不能直接删除。(只能删除空目录)

File类判断和获取功能

方法名说明
public booleanisDirectory()测试此抽象路径名表示的File是否为目录
public booleanisFile()测试此抽象路径名表示的File是否为文件
public booleanexists()测试此抽象路径名表示的File是否存在
public StringgetAbsolutePath()返回此抽象路径名的绝对路径名字字符串
public StringgetPath()将此抽象路径名转换为路径名字字符串
public StringgetName()返回由此抽象路径名表示的文件或目录的名称
public String[]list()返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[]listFiles()返回此抽象路径名表示的目录中的文件和目录的File对象数组

递归

  • 概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象
  • 递归解决问题的思路:
    • 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
    • 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
  • 递归解决问题需要找到两个内容:
    • 递归出口:否则会出现内存溢出
    • 递归规则:与原问题相似的规模较小的问题

字节流

字节流抽象基类

  • InputStream:这个抽象类是表示字节输入流的所有类的超类
  • OutputStream:这个抽象类是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都是以其父类名作为子类名的后缀

FileOutputStream字节流写数据

  • FileOutputStream:文件输出流用于将数据写入File

  • 常用的构造方法:

    方法名说明
    FileOutPutStream(String name)创建文件输出流以指定的名称写入文件
    FileOutPutStream(String name,boolean append)append参数为true时,写文件方式为追加写入
    FileOutPutStream(File file)创建文件输出流以指定的File对象写入文件
    FileOutPutStream(File file,boolean append)append参数为true时,写文件方式为追加写入
  • 常用的成员方法:

    方法名说明
    voidwrite(int b)指定的字节写入此文件输出流,参数为ASCII
    voidwrite(byte[] b)b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组的数据
    voidwrite(byte[] b,int off,int len)len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组的部分数据
    voidclose()关闭此文件输出流并释放与此流相关联的任何系统资源
  • 使用字节输出流写数据的步骤:

    • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
    • 调用字节输出流对象的写数据方法
    • 关闭文件,并释放资源
  • String中提供 getBytes() 方法可以将字符串转化为字节数组,方便数据的转化(Java中默认一个汉字用3个字节存储(UTF-8)

  • 当需要在文件中实现换行时,可以加上换行符(Idea中的文件阅读器可以自动识别各种换行符)

    • Windows:\r\n
    • Linux:\n
    • Mac:\r

字节流写数据的异常处理

  • finally:在异常处理时提供finally块来执行所有清除操作,比如IO流的释放资源

  • 特点:被finally控制的语句一定会执行,除非JVM退出

  • 常用的对FileNotFoundExceptionIOException异常的处理方法:

    FileOutputStream fos = null;
            try {
                fos = new FileOutputStream("Z:\\myOutputStream\\fos2.txt");
                fos.write("hello".getBytes());
            } catch (IOException e) { // 捕获创建对象文件找不到及调用write方法时可能产生的异常
                e.printStackTrace();
            } finally {
                if (fos != null) {  // 判断文件流对象是否创建成功(null),以免出现空指针报错
                    try {
                        fos.close();
                    } catch (IOException e) { // 捕获调用close方法时可能产生的异常
                        e.printStackTrace();
                    }
                }
            }
    
    • 注意:FileNotFoundException属于IOException的子类,捕获异常时只需要捕获IOException即可。
  • JDK7的改进方案:

    try(定义流对象1;定义流对象2...){
        可能出现异常的代码;
    } catch(异常类名 变量名){
        异常的处理代码;
    }
    
    	//自动释放资源,无需close
    

FileInputStream字节流读数据

  • FileInputStream:从文件系统中的文件获取输入字节

  • 常用的构造方法:

    方法名说明
    FileInputStream(String name)通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
  • 常用的成员方法:

    方法名说明
    intread()从该输入流读取一个字节的数据,返回值是字节数,若读不到数据,则返回 -1 
    intread(byte[] b)从该输入流读取最多b.length个字节的数据到一个字节数组,返回值是实际读取的字节个数,若读不到数据,则返回 -1 
    intread(byte[] b,int off,int len)从该输入流读取最多len个字节的数据到字节数组
    voidclose()关闭此文件输入流并释放与流相关联的任何系统资源
    • String中有构造方法String(byte[] b,int offset,int length) ,可使用匿名内部类的方法将字节数组转化为字符串输出

字节缓冲流

  • BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用

  • BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

  • 构造方法:

    • 字节缓冲输出流BufferedOutputStream(OutputStream out)
    • 字节缓冲输入流BufferedInputStream(InputStream in)
  • 字节缓冲流对象可以通过调用 writeread 方法操作文件

字符流

为什么会出现字符流

  • 由于字节流操作中文不是很方便,所以Java提供字符流
    • 字符流 = 字节流 + 编码表
  • 用字节流复制文本文件时,文本文件中也有中文,但是没有出现乱码问题,原因是最终底层操作会自动进行字节拼接成中文,底层是如何识别中文的呢?
    • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
  • 不同编码存储一个汉字的字节数
    • UTF-8:3个字节
    • GBK:2个字节

字符串的编码和解码

  • 编码:
    • byte[] getBytes():使用平台的默认字符集(Idea中默认UTF-8)将该String编码为一系列字节,将结果存储到新的字节数组中
    • byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
  • 解码:
    • String(byte[] bytes):通过使用平台的默认字符集(Idea中默认UTF-8)解码指定的字节数组来构造新的String
    • String(byte[] bytes,String charsetName):通过指定的字符集解码指定的字节数组来构造新的String

字符流抽象基类

  • Reader字符输入流的抽象类
  • Writer字符输出流的抽象类

InputStreamReader字符流读数据

  • 常用的构造方法:

    方法名说明
    InputStreamReader(InputStream in)创建一个使用默认字符集InputStreamReader对象
    InputStreamReader(InputStream in, String charsetName)创建一个使用指定字符集InputStreamReader
  • 常用的成员方法

    方法名说明
    intread()一次读一个字符数据,返回值是每个字符对应的UTF-8码,若读不到数据,则返回 -1 
    intread(char[] cbuf)一次读一个字符数组数据,返回值是实际读取的字符个数,若读不到数据,则返回 -1 

OutputStreamWriter字符流写数据

  • 字符流写数据时,写入的数据会暂时存储在缓冲区中,只要当刷新的时候,缓冲区中的数据才会被写入文件中(外存)

  • 常用的构造方法:

    方法名说明
    OutputStreamReader(InputStream in)创建一个使用默认字符集OutputStreamReader对象
    OutputStreamReader(InputStream in, String charsetName)创建一个使用指定字符集OutputStreamReader
  • 常用的成员方法:

    方法名说明
    voidwrite(int c)写一个字符
    voidwrite(char[] cbuf)写入一个字符数组
    voidwrite(char[] cbuf,int off,int len)写入字符数组的一部分
    voidwrite(String str)写一个字符串
    voidwrite(String str,int off,int len)写一个字符串的一部分
    voidflush()刷新流,还可以继续写数据
    voidclose()关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据

读写字符流便捷类

  • 转换流的名字比较长,而常见的操作都是按照本地默认编码实现的,所以为了简化书写,转换流提供了对应的子类
  • FileReader:用于读取字符文件的便捷类
    • FileReader(String fileName)
  • FileWriter:用于写入字符文件的便捷类
    • FileWriter(String fileName)
  • 注意:便捷类不提供指定编码读写的功能,若需要进行指定编码读写,还是要使用InputStreamReaderOutputStreamWriter

字符缓冲流

  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途。
    • BufferedWriter(Writer out)
  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途。
    • BufferedReader(Reader in)

字符缓冲流特有功能

  • BufferedWriter
    • void newLine():写一行行分隔符(换行符),行分隔符字符串由系统属性定义
  • BufferedReader
    • public String readLine():读一行文字。结果包括行的内容的字符串,不包括任何终止字符,如果流的结尾已到达,则为null

特殊操作流

标准输入输出流

  • System类中有两个静态的成员变量

    变量名说明
    public static finalInputStream in标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
    public static finalPrintStream out标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
  • 通常使用以下方法实现键盘录入数据:

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    // in为InputStream类的对象
    
  • 为解决以上书写麻烦等问题,Java提供了一个类实现键盘录入:

    Scanner sc = new Scanner(System.in);
    
  • 标准输出流的使用:

    PrintStream ps = System.out;
    ps.println();
    // print()和println()方法广泛应用于在控制台输出内容
    

打印流

  • 分类

    • 字节打印流:PrintStream
    • 字符打印流:PrintWriter
  • 特点

    • 只负责输出数据,不负责读取数据
    • 有特有的方法(例如printprintln等)
  • 字节打印流

    • PrintSteam(String fileName):使用指定的文件名创建新的打印流
  • 字符打印流

    • 构造方法:

      方法名说明
      PrintWriter(String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新
      PrintWriter(Writer out,boolean autoFlush)创建一个新的PrintWriterout:字符输出流;autoFLush:一个布尔值,若为真,则printlnprintfformat方法将刷新输出缓冲区

对象序列化流

  • 对象序列化:指的是将对象保存到磁盘中,或者在网络中传输对象

    这种机制就是使用一个字节序列不是一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息

    字节序列写到文件之后,相当于文件中持久保存了一个对象的信息

    反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

  • 对象序列化流:ObjectOutputStream

  • 对象反序列化流:ObjectInputStream

  • 构造方法:

    ObjectOutputStream(OutputStream out):产一个写入指定的OutputStreamObjectOutputStream

  • 序列化对象的方法:

    void writeObject(Object obj):将指定的对象写入ObjectOutputStream

  • 注意:

    • 一个对象想要被序列化,该对象所属的类必须实现Serializable接口
    • Serializable是一个标记接口,实现该接口,不需要重写任何方法

对象反序列化流

  • 构造方法:

    ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream

  • 反序列化对象的方法:

    Object readObject():从ObjectInputStream读取一个对象

serialVersionUID和transient

  • 一个可序列化的类在加载后会默认计算出序列化IDserialVersionUID)的值,若使用对象序列化流序列化了一个对象后,修改了对象所属的类文件,读取数据会出现问题,并抛出InvalidClassException异常

  • 为解决InvalidClassException异常的问题,可以给对象所属的类指定一个serialVersionUID

    private static final long serialVersionUID = 42L;
    
  • 若一个对象中的某个成员变量的值不想被序列化,可以给该成员变量加上transient关键字修饰,该关键字标记的成员变量不参与序列化过程

Properties

  • 概述

    • 是一个Map体系的集合类
    • Properties可以保存到流中或从流中加载
  • Properties作为集合的特有方法:

    方法名说明
    ObjectsetProperty(String key,String value)设置集合的键和值,都是String类型,底层调用Hashtable方法put
    StringgetProperty(String key)使用此属性列表中指定的键搜索属性
    Set<String> stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
  • PropertiesIO流结合的方法

    方法名说明
    voidload(InputStream inStream)从输入字节流读取属性列表(键和元素对)
    voidload(Reader reader)从输入字符流读取属性列表(键和元素对)
    voidstore(OutputStream out,String comments)将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
    voidstore(Writer writer,String comments)将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(Reader)方法的格式写入输出字符流

标题:Java IO流(八)
作者:wangdj
地址:https://qntop.com/articles/2024/10/28/1730128685393.html