学习IO很头疼?——那确实【复习计划】

    科技2022-08-15  96

    文章目录

    File类(java.io.File)静态成员变量构造方法:常用方法Filter过滤器的原理和使用文件路径 IO流分类字节流一切均为字节字节输出流字节输入流 字符流字符输入流字符输出流 流对象的异常处理处理流缓冲流字节缓冲输出流i字节缓冲输入流字符缓冲输出流字符缓冲输入流 转换流编码问题字符转化输入流字符转换输出流 序列化对象的序列化对象的反序列化 打印流继承结构图小案例 学习IO流头疼嘛?那确实是挺头疼的 😒,哈哈哈,慢慢总结你可以的!!! 学习IO流肯定得从File类说起啦

    File类(java.io.File)

    文件和目录路径名的抽象表示形式 Java把电脑中的文件和文件夹封装为一个File类,使得我们可以通过使用File对文件和文件夹进行操作

    静态成员变量

    1. String pathSeparator 与系统有关的路径分隔符 2. char pathSeparatorChar 3. String separator 与系统有关的默认名称分隔符 4. char separatorChar

    作用 * 由于在不同系统上路径分隔符与名称分隔符的差异,所以采用成员变量的形式进行文件路径的书写可以确保可移植性 * 如:Linux下路径分隔符为 “:” 名称分隔符为"/" 而windows下路径分隔符为";" 名称分隔符为"\"

    构造方法:

    File(String pathName);

    pathName:字符串路径名称路径可以是文件结尾,也可以是文件夹结尾路径可以是相对路径,也可以是绝对路径创建File对象,只是把字符串路径封装为file对象,不考虑路径的真实情况

    File(String parent,String child);

    优点:父路径和子路径单独书写,使用起来非常灵活,父路径和子路径都可以变化

    File(File parent,String child);

    优点: 父路径和子路径单独书写,使用起来非常灵活,父路径和子路径都可以变化父路径是file对象,可以使用一些File的一些方法对路径进行一些操作,再使用路径创建对象 File(URI uri);

    常用方法

    获取方法

    public String getAbsolutePath(): 返回该对象的绝对路路径字符串public String getName(): 返回file表示的文件或文件夹名称public String getPath(): 返回该file的文件路径字符串(创建对象时传入的路径字符串)public Long length(): 返回文件的大小(以字节为单位的),注意 文件夹的大小为0,若路径不存在,也返回0

    判断方法

    public boolean exists(): 此file表示的文件或目录是否存在public boolean isDirectory(): 此文件是否为一个目录public boolean isFile(): 此file表示的是否为文件

    创建和删除的方法

    public boolean createNewFile(): 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件

    返回值 true:当文件不存在时,创建文件并放回true、false:当文件存在时,不创建文件,返回false 注意: 此方法只能创建文件,并不能创建文件夹创建文件的路径必须存在,否则会抛出IOException

    public boolean mkdir(): 创建单级文件夹(返回值同上)

    注意:创建时看名称不能看类型,

    public boolean mkdirs(): 既可以创建单级的空文件夹,也可以创建多级文件夹(返回值同上)

    路径不存在时不会抛出异常

    public boolean delete(): 删除file对象表示的文件或文件夹

    delete方法时直接在硬盘删除文件,不走回收站,所以删除需要谨慎 File file=new File("a.txt"); file.mkdir(); // 可以创建并且返回true 但是创建的是名为a.txt文件夹

    4.File类遍历文件夹功能 1. public String [] list(): 返回一个String类型数组,表示file目录中所有的文件或目录 2. public File[] listFiles(): 返回一个file类型数组,表示file目录中所有的文件或目录 3. public File[] listFiles(FileFilter filter): 4. public File[] listFiles(FilenameFilter):


    Filter过滤器的原理和使用

    文件过滤器有两种:

    FileFilter接口

    用于过滤文件(file对象)抽象方法: boolean accept(File pathname) 测试指定抽象路径名是否包含在,某个路径名列表中

    FilenameFilter接口

    用于过滤文件名称抽象方法:boolean accept(File dir,String name) 测试指定文件是否应该包含在某一个文件列表中 File dir :构造方法中传递的被遍历的目录String name:使用listFiles方法遍历目录,获取的每一个文件/文件夹名称

    注意:

    在public File[] listFiles(FileFilter filter): 和public File[] listFiles(FilenameFilter): 执行中,listFile方法总共做了三件事

    listFiles方法会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹,并且封装为File对象listFiles方法会调用参数传递的过滤器中的accept方法listFiles方法会把遍历得到的每一个File对象传递给accept方法,作为参数pathname 返回值 当返回为true时,就会把传递过去的File对象保存到File数组中

    两个过滤器接口中都只有一个抽象方法,需要自己创建类实现接口,由于只有一个抽象方法所以还可以使用lamda表达式来简化书写 以下是两个过滤器使用的实例(搜索文件中)

    package filetest; import java.io.File; // 使用监听器对文件夹中所有的以 .java结尾的文件进行输出打印 public class IODemo01 { public static void main(String[] args){ // 使用了相对路径 File file=new File("../JavaSEReview"); allFile(file); } public static void allFile(File file){ File[] files=file.listFiles(new FileFilterImpl()); // 可以采用匿名内部类简化,也可以采用lamda表达式简化 if (files != null) { for (File file1:files ) { // 采用递归语句将文件夹逐一遍历 if(file1.isDirectory()){ allFile(file1); }else{ System.out.println(file1); } } } } }

    FileFilter接口的实现:

    package filetest;/* * @author:一身都是月~ * @date:2020/10/3 9:31 * */ import java.io.File; import java.io.FileFilter; public class FileFilterImpl implements FileFilter { @Override public boolean accept(File pathname) { if (pathname.getName().endsWith(".java")||pathname.isDirectory()) { return true; } return false; } }

    FilenameFilter接口的实现:

    package filetest;/* * @author:一身都是月~ * @date:2020/10/3 9:32 * */ import java.io.File; import java.io.FilenameFilter; public class FilenameFilterImpl implements FilenameFilter { @Override public boolean accept(File dir, String name) { File file=new File(dir,name); if (file.getName().endsWith(".java")||file.isDirectory()){ return true; } return false; } }

    文件路径

    绝对路径:是一个完整的路径 以盘符开始的路径 相对路径:是一个简化的路径 相对是指相对于当前项目的根目录如果使用当前项目的根目录,就可以将根目录的绝对路径用""替换,也可以省略

    注意: 1. 路径是不区分大小写的 2. 路径中的文件名称分隔符windows下使用反斜杠,而反斜杠是转义字符,所以需要使用两个反斜杠表示一个普通的反斜杠

    终于到大头IO流了

    IO流

    我想肯定有很多小伙伴才开始的时候会分不清输入和输出吧,反正当时我是这样的,先看一张 图,看完你就直到啦~

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IL4XXTXC-1601883703353)(C:\Users\Lenovo\Desktop\学习\笔记文档\IO流01.png)]

    分类

    IO流输入流输出流字节流InputStreamOutputStream字符流ReaderWriter

    字节流

    一切均为字节

    计算机中的一切文件数据(文本、视频、图片……)都是以2进制数字形式保存的,都是一个个的字节,所以在传输时一样如此,字节流可以传输任意文件数据,在操作流的时候,我们要时刻明白,无论使用什么流对象,底层的传输都是二进制数据

    字节输出流

    注意

    使用字节流写数据时,会把10进制的整数转换为2进制的整数,(注意写进文件的是字节),在我们打开记事本等文本编辑器的时候,查询编码表,将字节转换为字符表示 如果在 0-127 范围内,会查询ASCII表 其他数值则会查询系统默认编码表 可以结合String转换为字节数组,然后写入

    使用步骤 1. 创建一个OutputStream对象 2. 调用对象中的输出方法,把数据写入到文件中 3. 释放资源(流会占用一定的内存,使用完毕需要把内存清空)

    【OutputStream】是所有输出字节流的超类 定义了一些子类共性的方法 public void close() 关闭此输出流并释放与此流下相关联的任何系统资源public void flush() 刷新此输出流并强制任何缓冲的输出字节流被写出public void write(byte[] b) 将b.length个字节从指定的数组写到此输出流中 如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表如果写的第一个字节是负数,那第一个字节会和第二个字节组成一个中文显示,查询系统默认编码表(GBK) public void write(byte[] b , int off , int len) 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流中public abstract void write(int b) 将指定的字节输出流
    FileOutputStream:文件字节输出流 构造方法 FileOutputStream(String name) 创建一个指向指定名称的文件中写入数据的输出文件流-----name 为文件路径FileOutputStream(File file) 创建一个向指定file对象表示的文件中写入数据的文件输出流FileOutputStream(String name,boolean append)FileOutputStream(File file,boolean append) append表示是否追加写入,如果为true,创建对象的时候不会覆盖原文件,继续在文件末尾追加书写,如果为false:则会创建新文件覆盖原文件 构造方法作用: 创建一个FileOutputStream对象会根据构造方法中传递的文件/文件路径,创建一个空的文件会把FileOutputStream对象指向创建好的文件

    字节输入流

    注意

    使用字节流读取数据时,得到的是对应的字节数据,所以可以使用char转型从而得到字符数据 可以使用read(byte[] b) 将数据读取到字符数组中,然后可以用String中一个构造方法转换为字符串,- String(byte[] bytes) String(byte[] bytes, int offset , int length)

    使用步骤 1. 创建一个InputStream对象 2. 调用对应的读取方法 3. 释放资源

    【InputStream】是所有字节输入流的超类

    定义了一些子类共用的方法 int read() 从输入流中读取数据的下一个字节,当读取到文件末尾时,返回-1int read(byte[] b)void close()

    FileInputStream:文件字节输入流

    构造方法 FileInputStream(String name)FileInputStream(File file)参数: String name:文件路径File file:文件 构造方法的作用 创建一个FileInputStream对象会把FileInputStream对象指定构造方法中要读取的文件 常用方法 public int read();public int read(byte[] bytes); 关于参数 bytes[] 起到缓冲作用,存储每次读取到的多个字节数组长度一般定义为1024(1kb)或者1024的整数倍 返回值int 表示每次读取的有效字节个数,当达到数据末尾则返回-1 读取数据的原理(硬盘------>内存) java程序------> JVM-------> OS(操作系统)------->OS读取 数据的方法---->读取文件.

    字符流

    字符输入流

    【Reader】 所有字符输入流的超类

    定义了一些子类共用的方法 .

    FileReader

    继承自inputStreamReader,InputStreamReader又继承自Reader构造方法 FileReader(String name);FileReader(File file);

    此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的,想要自己指定这些值,需要结合转换流使用

    字符输出流

    使用步骤 1. 创建FileWriter对象,构造方法中绑定数据写入的目的地 2. 使用FileWriter中的方法write,把数据写入到内容缓冲区(字符转换为字节) 3. 使用FileWriter中的flush,把内存缓冲区中的数据,刷新到文件中 4. 释放资源(会先把缓冲区的数据刷新到新文件中)

    注意 * 虽然参数为int类型的四个字节,但是只会保留一个字符的信息写出 * 未调用close方法,数据只是保存到了缓冲区。并未写入到文件中

    【Writer】 所有字符输出流的超类FileWriter

    流对象的异常处理

    原来的处理方式 public static void copyFile(){ OutputStream os=null; InputStream is=null; try { os=new FileOutputStream("../JavaSEReview/src/filetest/copy.txt",false); is=new FileInputStream("../JavaSEReview/src/filetest/IODemo01.java"); byte[] bytes=new byte[1024]; int len; while((len=is.read(bytes))!=-1){ os.write(bytes,0,len); } } catch (IOException e) { e.printStackTrace(); }finally { try { os.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } } JDK7新特性

    可以在try后边增加一个(),在括号中定义流对象,那么这个流对象的作用域就在try中有效,try代码执行完毕后,会自动把流对象释放,不用再写finally

    于是代码可以这样写

    public static void copyFile(){ try (OutputStream os=new FileOutputStream("../JavaSEReview/src/filetest/copy.txt",false); InputStream is=new FileInputStream("../JavaSEReview/src/filetest/IODemo01.java");){ byte[] bytes=new byte[1024]; int len; while((len=is.read(bytes))!=-1){ os.write(bytes,0,len); } } catch (IOException e) { e.printStackTrace(); } } JDK9新特性

    在try前边可以定义流对象,在try后边的()中可以直接引入流对象的名称(变量名),在try代码执行完毕后,流对象也可以自动释放掉,不用写finally

    我这里由于JDK版本并没有升级就不做案例了,不过感觉JDK9版本的这个新特性有点多余,因为try。catch后还是得throws,当然这个我也不是很清楚欢迎大家补充

    处理流

    缓冲流

    字节缓冲流 : BufferedInputStream , BufferedOutputStream字符缓冲流 : BufferedReader , BufferedWriter
    字节缓冲输出流i

    BufferedOutputStream继承自OutputStream

    继承自父类的共性成员方法:

    public void close()public void flush()public void write(byte[] b)public void write(byte[] b , int off , int len)public abstract void write(int b)

    构造方法

    BufferedOutputStream(OutputStream out) 创建一个新的缓冲流,将数据写到指定的底层输出流BufferedOutputStream(OutputStream out , int size) 创建一个新的缓冲流,以将具有指定缓冲区大小的数据写入指定的底层输入流 参数: OutputStream字节输出流,我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高其写入效率int size:指定缓冲区大小,可以不指定

    使用步骤

    创建FileOutputStream对象,构造方法中绑定输出的目的地创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,使用BufferedOutputStream对象的write方法,将数据写入到内部缓冲区使用BufferedOutputStream对象中的flush方法,将内部缓冲区的文件刷新到文件中释放资源(会先调用flush方法,所以第四步可以省略)
    字节缓冲输入流
    字符缓冲输出流

    特有成员方法

    void newLine() 写一个行分隔符,会根据不同的操作系统,获取不同的换行符windows: \r\nLinux: /nMac:/r

    使用步骤:

    创建字符缓冲输出流对象,构造方法中传递字符输出流调用字符缓冲流中的方法write,把数据写入到内存缓冲区调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据刷新到文件中释放资源
    字符缓冲输入流
    特有成员方法 String readline(): 读取一个文本行 行的终止符号,通过下列字符之一即可认为是某行中止:换行“\n”,回车"\r"或回车后跟换行返回改行内容的字符串,不包含任何终止符,如果到达末尾,返回null

    转换流

    编码问题

    在IDEA中,使用FileReader读取项目中的文本文件,由于IDEA的设置,都是默认为UTF-8编码所以并没有出现问题,然而,在读取创建的本地的非UTF-8编码的文件时,就会出现乱码问题

    UTF-8 国际标准码表,用三个字节存储中文字符GBK 中文码表,使用两个字节存储中文字符

    字符转化输入流

    InputStreamReader InputStreamReader是字节流通向字符流的桥梁,他使用指定的charset读取字节并将其解码为字符继承自Reader,所以有共用的成员方法,这里就不过多赘述了

    字符转换输出流

    OutputStreamWriter OutputStreamWriter 是字符流通向字节流的桥梁,可以使用指定的charset将要写入流中的字符编码成字节继承自Writer,所以有共用的成员方法构造方法 OutputSteamWriter(OutputStream out) 默认使用UTF-8编码表OutputStreamWriter(OutputStream out , String charsetName) 创建使用指定字符集的OutputStreamWriter

    序列化

    类通过实现Serializable接口以启用其序列化功能,未实现接口的类将无法使其任何状态序列化与反序列化,序列化接口没有方法和字段,仅用于标识可序列化的语义 如果不实现接口,则会抛出NotSerializableException异常

    注意

    静态的成员变量是不能被序列化的

    static 静态优先于非静态加载到内存中(静态优先于对象进入到内存中)

    transient关键字修饰的成员变量也不能被序列化

    transient:瞬态关键字,被transient修饰成员变量,不能被序列化

    序列化运行时使用一个称为serialVersionUID的版本号与每个可序列化类相关联,该序列hao 在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类,如果接收者加载的该对象的serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException异常,所以在每次修改了类的定义后,都会给class文件生成一个新的序列号,导致之前序列化的对象反序列化失败

    解决方法:无论是否对类的定义修改,都不重新生成新的序列号(可以手动给类添加一个序列号) 在可序列化类中可以通过声明名为“serialVersionUID”字段,**(该字符必须是静态的static、最终的final、long型字段)**显示的声明自己的serialVersionUID;

    对象的序列化

    把对象以流的方式写入到文件,叫写对象,也叫对象的序列化

    ObjectOutputStream:对象的序列化流

    构造方法:

    ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream的ObjectOutputStream

    特有方法

    writerObject(Object object) 将指定的对象写入到ObjectOutputStream流中

    对象的反序列化

    把文件中保存的对象,以流的方式读取出来,叫读对象,也叫对象的反序列化

    ObjectInputStream:对象的反序列化流

    特有方法 Object readObject() 除了声明了IOException异常外,还有ClassNotFoundException异常

    打印流

    PrintStream:打印流 PrintStream 为其他输出流添加了功能,使它们能够方便的打印各种数据值表示形式

    特点:

    只负责数据的输出,不负责数据的读取与其他输出流不同,PrintStream永远不会抛出IOException异常有自己的自动的flush功能继承自OutputStream

    构造方法:

    PrintStream(File file)PrintStream(OutputStream out )PrintStream(String fileName)其余方法可到java api中查询

    注意:

    如果使用继承自父类的write方法写数据,那么查看数据时就会查询编码表如果使用PrintStream特有的方法print/println 方法写数据,写的数据原样输出可以改变输出语句的目的地(打印流的刘翔) 输出语句(System.out.print())默认在控制台输出,可以使用System.setOut(PrintStream printStream)方法,改变默认的输出的目的地

    继承结构图

    小案例

    用不同的方法进行文件的复制(字节流、字符流、缓冲流、打印流……)改变文件的编码方式,使用转换流练习用序列化存储一个对象集合,并反序列化输出
    Processed: 0.022, SQL: 8