Java学习笔记----File类与IO流

第五章:File类与IO流

第一节:File类

1.1 概述

java.io.File类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作

Java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作

我们可以使用File类的方法

创建一个文件/文件夹

删除文件/文件夹

获取文件/文件夹

判断文件/文件夹是否存在

对文件夹进行遍历

获取文件的大小

File类是一个与系统无关的类,任何操作系统都可以使用这个类中的方法

**重点:**记住这三个单词——file:文件 directory:文件夹/目录 path:路径

1.2 File类的静态成员变量
  • static String pathSeparator:与系统有关的路径分隔符,为了方便,它被表示为一个字符串
System.out.println(File.pathSeparator);//路径分隔符 Windows:分号;linux:冒号
  • static char pathSeparatorChar:与系统有关的路径分隔符

  • static String separator:与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串

System.out.println(File.separator);
//文件名称分隔符 Windows:反斜杠\ 		linux:正斜杠/
操作路径:路径不能写死了
C:\develop\a\a.txt	Windows
C:/develop/a/a.txt	Linux
"C:"+File.separator+"develop"+File.separator+"a"+File.separator+"a.txt"
  • static char separatorChar:与系统有关的默认名称分隔符
1.3 绝对路径和相对路径

**绝对路径:**是一个完整的路径,以盘符(C: D:)开始的路径

C:\\Users\itcast\\IdeaProjects\\a\\a.txt

**相对路径:**是一个简化的路径,是相对于当前项目的根目录

如果使用当前项目的根目录,路径可以简化书写

a.txt(可以省略项目的根目录)

注意:

1、路径是不区分大小写

2、路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠

1.3 File类的构造方法
  • public File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的File实例

**String pathname:**字符串的路径名称
路径可以是以文件结尾,也可以是以文件夹结尾;可以是相对路径,也可以是绝对路径;可以存在,也可以不存在。创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况

//绝对路径
File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f1);//D:\Java\CG\38.穆娅.jpg  重写了Object类的toString方法

//相对路径
File f2=new File("B.txt");
System.out.println(f2);//B.txt
  • public File(String parent,String child):从父路径名字符串和子路径名字符串创建新的File实例

**参数:**把路径分成了两部分

String parent:父路径

String child:子路径

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

File f3=new File("D:\\Java\\CG\\","38.穆娅.jpg");
System.out.println(f3);//D:\Java\CG\38.穆娅.jpg
  • public File(File parent,String child):从父抽象路径名和子路径名字符串创建新的File实例

参数:把路径分成了两部分

**File parent:**父路径

**String Child:**子路径

好处:

1、父路径和子路径可以单独书写,使用起来非常灵活;父路径和子路径都可以变化

2、父路径是File类型,可以使用File类的方法对路径进行一些操作,再使用路径创建对象

File f4=new File("D:\\Java\\CG\\");
File f5=new File(f4,"38.穆娅.jpg");
System.out.println(f5);//D:\Java\CG\38.穆娅.jpg
1.4 File类的常用方法
获取功能的方法:
  • public String getAbsolutePath():返回此File类的绝对路径名字符串

获取的构造方法中传递的路径,无论路径是绝对的还是相对的,getAbsolutePath方法返回的都 是绝对路径

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f1.getAbsolutePath());//D:\Java\CG\38.穆娅.jpg

File f1=new File("38.穆娅.jpg");
System.out.println(f1.getAbsolutePath());//D:\Java\CG\38.穆娅.jpg
  • public String getPath():将此File转换为路径名字符串

获取的构造方法中传递的路径,但是getPath方法是什么形式的就是什么形式的

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f1.getAbsolutePath());//D:\Java\CG\38.穆娅.jpg

File f1=new File("38.穆娅.jpg");
System.out.println(f1.getPath());//38.穆娅.jpg
  • public String getName():返回由此File表示的文件或目录的名称

获取的就是构造方法传递路径的结尾部分,要么是文件,要么是文件夹

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f1.getName());//38.穆娅.jpg

File f2=new File("D:\\Java\\CG\\");
System.out.println(f2.getName());//CG
  • public long length():返回由File表示的文件的长度

获取的是构造方法指定的文件的大小,以字节为单位

注意:

1、文件夹是没有大小概念的,不能获取文件夹大小

2、如果构造方法中给出的路径不存在或者获取的对象是文件夹,那么length方法的返回值是0

File f3=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f3.length());//192798(字节)
判断功能的方法
  • public boolean exists():此File表示的文件或目录是否实际存在

    存在:true 不存在:false

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
System.out.println(f1.exists());//true
  • public boolean isDirectory():此File表示的是否为目录

用于判断构造方法中给定的路径是否以文件夹结尾

是:true 否:flase

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
File f2=new File("D:\\Java\\CG");
System.out.println(f1.isDirectory());//flase
System.out.println(f2.isDirectory());//true
  • public boolean isFile():此File表示的是否为文件

用于判断构造方法中给定的路径是否以文件结尾

是:true 否:flase

File f1=new File("D:\\Java\\CG\\38.穆娅.jpg");
File f2=new File("D:\\Java\\CG");
System.out.println(f1.isFile());//true
System.out.println(f2.isFile());//false

注意:

电脑的硬盘中只有文件/文件夹,isDirectory与isFile两个方法是互斥的

**isDirectory与isFile的使用前提:**路径必须是存在的,否则都返回flase

File类创建删除功能的方法
  • public boolean creatNewFile():当且仅当该名称的文件尚不存在时,创建一个新的空文件

创建文件的路径和名称在构造方法中给出(构造方法的参数)

返回值:布尔值 true:文件不存在,创建文件,返回true flase:文件存在,不会创建,返回false

注意:

1、此方法只能创建文件,不能创建文件夹

2、创建文件的路径必须存在,否则会抛出异常

File f1=new File("D:\\Java\\CG\\a.txt");
System.out.println(f1.createNewFile());//true			creatNewFile声明抛出了IOException,我们调用这个方法,就必须处理这个异常,要么throws,要么trycatch

File f1=new File("D:\\Java\\CG");
System.out.println(f1.createNewFile());//true 没有报错,但是生成了一个不能打开的文件,不要被名称迷惑,要看类型

File f2=new File("D:\\Java1\\CG\\a.txt");
System.out.println(f2.createNewFile());//路径不存在,抛出IOException异常
  • public boolean delete():删除由此File表示的文件或目录

此方法,可以删除构造方法路径中给出的文件/文件夹

返回值:布尔值 true:文件/文件夹删除成功,返回true false:文件夹中有内容,不会删除,返回false;构造方法中路径不存在,返回false

注意:delete方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎

  • public boolean mkdir:创建由File表示的目录
System.out.println(f3.delete());//true

创建单级空文件夹

创建文件夹的路径和名称在构造方法中给出(构造方法的参数)

返回值:布尔值 true:文件夹不存在,创建文件夹,返回true flase:文件夹存在,不会创建,返回false,构造方法中给出的路径不存在也返回false

File f2=new File("D:\\Java\\CG\\a");
System.out.println(f2.mkdir());//true
  • public boolean mkdirs():创建由此File表示的目录,包括任何必需但不存在的父目录

既可以创建单级文件夹,也可以创建多级文件夹

路径不存在抛出异常,路径不存在不会创建

File f3=new File("D:\\Java\\CG\\a\\aa\\aaa\\aaaa");
System.out.println(f3.mkdirs());//true
1.5 目录的遍历
  • public String[] list():返回一个String数组,表示该File目录中所有的子文件或目录

遍历构造方法中所给出的目录,会获取目录中所有文件/文件夹的名称,把获取到的多个名称存储到一个String类型的数组中

可以获取到隐藏文件夹

File f1=new File("D:\\Java\\CG");
String[] st=f1.list();
for (String s:st) {
	System.out.println(s);
}
  • public File[] listFiles():返回一个File数组,表示该File目录中所有的子文件或目录

遍历构造方法中所给出的目录,会获取目录中所有文件/文件夹,把获取到文件/文件夹封装成为File对象,多个File对象存储到File数组中

File f2=new File("D:\\Java\\CG");
File[] files=f2.listFiles();
for (File file:files) {
	System.out.println(file);
}//文件的路径也打印出来了

注意:

list方法和listFiles方法遍历的是构造方法中给出的目录

1、如果构造方法中给出的目录路径不存在,会抛出空指针异常

2、如果构造方法中给出的路径不是一个目录,也会抛出空指针异常

第二节:递归

2.1 概述

**递归:**指在当前方法内调用自己的这种现象

递归的分类:

直接递归:方法调用自己

**间接递归:**可以A方法调用B方法,B方法调用C方法,C方法调用A方法

注意:

1、递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出

2、在递归中虽然有限定条件,但是递归次数不能太多,否则也会发生栈内存溢出

3、构造方法禁止递归:构造方法是创建对象使用的,一直递归会导致内存中有无数个对象,直接编译报错

**使用前提:**当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递归

栈内存溢出示意图:

栈内存溢出

第三节:文件过滤器FileFilter

java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器

**作用:**用来过滤文件

抽象方法:

  • boolean accept(File pathname):测试pathname是否应该包含在当前File目录中,符合则返回true

**参数:**File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象

java.io.FilenameFilter接口:用于过滤文件名称

作用:用于过滤文件名称

**抽象方法:**用来过滤文件的方法

  • boolean accept(File dir,String name):测试指定文件是否应该包含在某一文件列表中

    参数:File dir :构造方法中传递的被遍历的目录 String name:使用ListFiles方法遍历目录,获取的每一个文件/文件夹的名称

注意:两个过滤器结构是没有实现类的,需要我们自己写实现类,重写过滤的方法accept,在方法中自己定义过滤的规则

listFiles方法一共做了3件事:

1、listFiles方法会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹---->封装为File对象

2、listFiles方法会调用参数传递的过滤器中的方法accept

3、listFiles方法会把遍历得到的每一个File对象,传递给accept方法的参数:pathname

accept方法返回值是一个布尔值:

true:就会把传递过去的File对象保存到File数组中

false:就不会把传递过去的File对象保存到File数组中

过滤的规则:

在accept方法中,判断File对象是否以对应字符串结尾,是就返回true,不是就返回false

第三节:IO字节流

3.1 IO概述

数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input输出output,即流向内存是输入流流出内存是输出流

Java中I/O操作主要是使用java.io包下的内容,进行输入、输出操作,输入也叫做读取数据,输出也叫做写出数据

IO

3.2 IO的分类

根据数据的流向分为:输入流输出流

  • **输入流:**把数据从其他设备上读取到内存中的流
  • **输出流:**把数据从内存中写出到其他设备上的流

格局数据的类型分为:字节流字符流

顶级父类们:

输入流输出流
字节流字节输入流
InputStream
字节输入流
OutputStream
字符流字符输入流
Reader
字符输出流
Writer
3.3 字节流
3.3.1 一切皆为字节

一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据

3.3.2 字节输出流【OutputStream】

java.io.OutputStreamextendsOutputstream ,它是抽象类,是表示字节输入流的所有类的超类,将指定的字节信息写出到目的地。

构造方法:

  • FileOutputStream(File file):创建一个向指定File对象表示的文件中写入数据的文件输入流

    **参数:**写入数据的目的地 File file:目的地是一个文件

  • FileOutputStream(FileDescriptor fdobj):创建一个向指定文件描述符处写入数据的输出文件流,该文件描述符表示一个到文件系统中的某个实际文件的现有连接

  • FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流

    **参数:**写入数据的目的地 String name:目的地是一个文件的路径

构造方法的作用:

1、创建了一个FileOutStream对象

2、会根据构造方法中传递的文件/文件路径,创建一个空的文件

3、会把FileOutputStream对象指向创建好的文件

它定义了字节输出流的基本共性功能方法,定义了一些子类共性的成员方法

  • public void close():关闭此输出流并释放与此流相关联的任何系统资源
  • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出
  • public abstract void write(int b):将指定的字节输出流
public static void main(String[] args) throws IOException {
        FileOutputStream fos=new FileOutputStream("D:\\Java\\CG\\a.txt");
        fos.write(97);
        fos.write(115);
        fos.close();
    }//as

写入数据的原理:(内存---->硬盘)

java程序---->JVM(java虚拟机)---->OS(操作系统)----->OS调用写数据的方法----->把数据写入到文件中

字节输出流的使用步骤(重点):

1、创建一个FileOutputStream对象,构造方法中传递写入数据的目的地

2、调用FileOutputStream对象中的方法write,把数据写入到文件中

3、释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序效率)

3.3.3 文件存储的原理和记事本打开文件的原理:

文件存储的原理和记事本打开文件的原理

3.3.4 字节输出流写多个字节的方法
  • public void write(byte[] b):将b.length字节从指定的字节数组写入此输入流

**一次写多个字节:**如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表,如果写的第一个字节是负数,那第一个字节会和第二个字节组成一个中文显示,查询系统默认码表(GBK)

FileOutputStream fos=new FileOutputStream(new File("D:\\Java\\CG\\aa.txt"));
byte[] bytes={-65,-67,-68,69};
fos.write(bytes);
fos.close();
  • public void write(byte[] b,int off,int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输入流

把字节数组的一部分写入到文件中,从指定的字节数组写入len字节,从偏移量off开始输出到此输出流

int off:数组的开始索引 **int len:**写几个字节

FileOutputStream fos=new FileOutputStream(new File("D:\\Java\\CG\\aa.txt"));
byte[] bytes={-65,-67,-68,69};
fos.write(bytes,1,2);
fos.close();

**写入字符串的方法:**可以使用String类中的方法.getBytes()把字符串转换为字节数组

3.3.5 字节输出流的续写与换行

**追加写/续写:**使用两个参数的构造方法

  • FileOutputStream(String name,boolean append):创建一个具有指定name的文件中写入数据的输出文件流

  • FileOutputStream(File file,boolean append):创建一个向指定File对象文件中写入数据的文件输出流

    参数: String nameFile file:写入数据的目的地

    boolean append:追加写开关 true:创建对象不会覆盖原文件,继续在文件的末 尾追加写数据 false:创建一个新文件,覆盖源文件

**写换行:**写换行符号

​ windows:\r\n Linux:/n mac:/r

public static void main(String[] args) throws IOException {
        FileOutputStream fos=new FileOutputStream("D:\\Java\\CG\\a.txt",true);//续写
        for (int i = 0; i <10 ; i++) {
            fos.write("你好\r\n".getBytes(StandardCharsets.UTF_8));//换行写
        }
        fos.close();
    }
3.3.6 字节输入流【InputStream】

java.io.InputStreamextends InputStream抽象类是表示字节输入流所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法

**作用:**把硬件文件中的数据读取到内存中使用

构造方法:

  • FileInputStream(String name)

  • FileInputStream(File file)

    **参数:**读取文件的数据源 String name:文件的路径 File file:文件

    构造方法的作用:

    1、会创建一个FileInputString对象

    2、会把FileInputStream对象指向构造方法中要读取的文件

3.3.7 字节输入流读取字节数据

读取数据的原理(硬盘---->内存):

Java程序-----JVM----->OS----->OS读取数据的方法----->读取文件

字节输入流的使用步骤:

1、创建一个FileInputStream对象,构造方法中绑定要读取的数据源

2、使用FileInputStream对象中的方法read,读取文件

3、释放资源

  • public void close():关闭输入流并释放与此流相关联的任何系统资源
  • public abstract int read():从输入流中读取数据的下一个字节

遍历一个文本文件的所有内容:

FileInputStream fis=new FileInputStream("D:\\Java\\CG\\a.txt");
int s=0;
while((s=fis.read())!=-1) {
        System.out.println((char)s);
	}
fis.close();

布尔表达式:(s-fis.read()!=-1)
    1fisread():读取一个字节
    2、s=fis.read():把读取的字节赋给变量s
    3(s-fis.read())!=1:判断变量s是否不等于-1
3.3.8 字节输入流一次读取一个字节的原理

字节输入流一次读取一个字节的原理

3.3.9 字节输入流一次读取多个字节
  • public int read(byte[] b):从输入流中读取一些字节流,并把它存储到字节数组b中

String类的构造方法:

**String(byte[] bytes):**把字节数组转换为字符串

String(byte[] bytes,int offset,int length):把字节数组的一部分转换为字符串

​ offset:数组的开始索引 length:转换的字节个数

byte[]的作用:起到缓冲的作用,存储每次读取到的多个字节,数组的长度一般定义为1024(1kb)或者1024的整数倍

​ 方法的返回值int是:每次读取的有效字节个数

FileInputStream fis=new FileInputStream("D:\\Java\\CG\\aa.txt");
byte[] bytes=new byte[2];
fis.read(bytes);
System.out.println(Arrays.toString(bytes));//[97,115]
System.out.println(new String(bytes));//as
fis.close();

一次读取多个字节的原理:

一次读取多个字节的原理

第四节:IO字符流

当使用字节流读取文本文件时,可能会有一个小问题,就是遇到中文时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件

4.1 字符输入流【Reader】

java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

java.io.FileReader extends InputStreamReader extends Reader

FireReader:文件字符输入流

作用:把硬盘文件中的数据以字符的方式读入到内存中

构造方法:

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

**参数:**读取文件的数据源

String fileName:文件的路径 **File file:**一个文件

FileReader构造方法的作用:

1、会创建一个FileReader对象

2、会把FileReader对象指向要读取的文件

4.2 字符输入流读取字符数据

字符输入流的使用步骤:

1、创建FileReader对象,构造方法中绑定要读取的数据源

2、使用FileReader对象中的方法read读取文件

3、释放资源

  • public void close():关闭此流并释放与此流相关联的任何系统资源
  • public int read():从输入流读取一个字符
FileReader fr=new FileReader("D:\\Java\\CG\\aa.txt");
int s=0;
while((s=fr.read())!=-1) {
	System.out.print((char)s);
}
fr.close();
  • public int read(char[] cbuf):从输入流中读取一些字符,并将他们存储到字符数组cbuf中
FileReader fr=new FileReader("D:\\Java\\CG\\aa.txt");
int s=0;
char[] chars=new char[1024];
while((s=fr.read(chars))!=-1)
	System.out.println(new String(chars,0,s));
fr.close();
4.3 字符输出流【Writer】

java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法

java.io.FileWriter extends OutputStreamWriter extends Writer

**FileWriter:**文件字符输出流

**作用:**把内存中字符数据写入到文件中

构造方法:
  • FileWriter(File file):根据给定的File对象构造一个FileWriter对象

  • FileWriter(String fileName):根据给定的文件名构造一个FileWriter对象

    **参数:**写入数据的目的地

    **String fileName:**文件的路径 **File file:**是一个文件

    构造方法的作用:

    1、会创建一个FileWriter对象

    2、会根据构造方法中传递的文件/文件的路径,创建文件

    3、会把FileWriter对象指向创建好的文件

成员方法:
  • void write(int c):写入单个字符
  • void flush():刷新该流的缓冲
  • void close():关闭此流,但要先刷新它
FileWriter fw=new FileWriter("D:\\Java\\CG\\a.txt");
fw.write(97);
fw.flush();
fw.close();
  • void write(char[] cbuf):写入字符数组
FileWriter fw=new FileWriter("D:\\Java\\CG\\b.txt");
char[] chars={'a','b','c','d','e'};
fw.write(chars);
fw.close();
  • abstract void write(char[] cbuf,int off,int len):写入字符数组的某一部分,off是数组的开始索引,len是写入的字符个数
  • void write(String str):写入字符串
  • void write(String str,int off,int len):写入字符串的某一部分,off是字符串的开始索引,len是写的字符个数
FileWriter fw=new FileWriter("D:\\Java\\CG\\b.txt");
char[] chars={'a','b','c','d','e'};
fw.write(chars);
fw.write(chars,1,3);
fw.write("你好你好!");
fw.write("你好你好",0,3);
fw.close();
字符输出流的使用步骤:

1、创建一个FileWriter对象,构造方法中绑定要写入数据的目的地

2、使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)

3、使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中

4、释放资源(会先把内存缓冲区中的数据刷新到文件中)

关闭和刷新:

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中,但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要使用flush方法

  • flush:刷新缓冲区,流对象可以继续使用
  • close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
字符输出流的续写和换行

**续写和换行:**类似于

**续写:**追加写:使用两个参数的构造方法

  • FileWriter(String fileName,boolean append)

  • FileWriter(File file,boolean append)

    参数:

    **String fileName,File file:**写入数据的目的地

    boolean append:续写的开关,true:不会创建新文件覆盖原文件;false:创建新的文件覆盖原文件

**换行:**换行符号

windows:\r\n linux:\n mac:\r

第五节:IO 异常处理

5.1 使用try catch finally处理流中的异常

在JDK 1.7之前使用try catch finally 处理流中的异常

格式:

try{
    可能产生异常的代码
}catch(异常类的变量 变量名){
    异常的处理逻辑
}finally{
    一定会执行的代码
    资源释放
}

例子:

public class IO_try_catch {
    public static void main(String[] args) {
        //提高fw的作用域,让finally可以使用
        //变量在定义的时候可以没有值,但是使用的时候必须有值
        //fw=new FileWriter("D:\\Java\\CG\\bb.txt");执行失败,fw没有值,fw.close会报错
        FileWriter fw = null;
        try {
            //可能会产生异常的代码
            fw = new FileWriter("D:\\Java\\CG\\bb.txt");
            for (int i = 0; i < 10; i++) {
                fw.write("Hello World" + i + "\r\n");
            }
        } catch (IOException e) {
            //异常的处理逻辑
            System.out.println(e);
        } finally {
            //一定会执行的代码
            //创建对象失败了,fw的默认值是NULL,null是不能调用方法的,会抛出空指针异常,需要加一个判断,不是null再把资源释放
            if (fw != null) {
                try {
                    //fw.close方法声明抛出了IOException异常对象,所以我们就得处理这个异常对象,要么throws
                    // ,要么try catch
                    fw.close();
                } catch (IOException e) {
                    System.out.println(e);
                } finally {

                }
            }
        }
    }
}
5.2 JDK7和JDK9流中异常的处理

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

格式:

try(定义流对象;定义流对象...){
    可能会产生异常的代码
}catch(异常类变量 变量名){
    异常的处理逻辑
}

例子:

public class JDK_7 {
    public static void main(String[] args) {
        try(
                FileWriter fw=new FileWriter("D:\\Java\\CG\\bbb.txt");
                FileReader fr=new FileReader("D:\\Java\\CG\\bbb.txt");
            ){
            fw.write("Are you OK!\n\r");
            fw.close();
            int s=0;
            char[] chars=new char[1024];
            while((s=fr.read(chars))!=-1)
                System.out.println(new String(chars,0,s));
            fr.close();
        }
        catch (IOException e){
            System.out.println(e);
        }
    }
}

JDK 9的新特性:

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

格式:

A a=new A();
B b=new B();
try(a;b){
    可能会产生异常的代码
}catch(异常类变量 变量名){
    异常的处理逻辑
}

例子:

public class JDK_9 {
    public static void main(String[] args) throws IOException {
        FileReader fr=new FileReader("D:\\Java\\CG\\c.txt");
        FileWriter fw=new FileWriter("D:\\Java\\CG\\c.txt");
        try(fr;fw){
            fw.write("Hello \n\rWord!");
            int s=0;
            char[] chars=new char[1024];
            while((s=fr.read(chars))!=-1)
                System.out.println(new String(chars,0,s));
        }
        catch (IOException e){
            System.out.println(e);
        }
    }
}

9不如7方便

第六节:Properties 属性集

6.1 概述

java.util.Properties extends Hashtable<k,v> implents Map<k,v>,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多java类使用,比如获取系统属性时,System.getProperties 方法就是返回一个Properties 对象

它是唯一一个和IO流相结合的集合,是一个双列集合,key和value默认都是字符串,有一些操作字符串的特有方法

功能:

1、可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储

2、可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

6.2 Properties类
构造方法
  • public Properties():创建一个空的属性列表
Properties prop=new Properties();
基本的存储方法
  • public Object setProperty(String key,String value):保存一对属性
prop.setProperty("张三","168");
  • public String getProperty(String key):通过key,找到value值,此方法相当于Map集合中的get(key)方法
  • public Set<String> stringPropertyNames():返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
Set<String> set=prop.stringPropertyNames();
for (String s:set) {
	System.out.println(s+" "+prop.getProperty(s));
}
李四 178
张三 168
王五 188
6.3 Properties集合中的方法store
  • public void store(OutputStream out,String comments)
  • public void store(Writer writer,String comments)

参数:

**OutputStream out:**字节输出流,不能写入中文

Writer writer:字符输出流,可以写中文

String comments:注释,用来解释说明保存的文件是做什么的。不能使用中文,会产生乱码,默认是Unicode编码,一般使用""空字符串

使用步骤:

1、创建一个Properties集合对象,添加数据

2、创建字节输出流/字符输出流,构造方法中绑定要输出的目的地

3、使用Properties集合中的方法store,把集合中的临时数据持久化写入到硬盘中存储

4、释放资源

prop.store(new FileWriter("D:\\Java\\CG\\bbb.txt"),"");

FileWriter fw=new FileWriter("D:\\Java\\CG\\ccc.txt");
prop.store(fw,"");
fw.close();
6.4 Properties集合中的方法load
  • public void load(InputStream inStream)
  • public void load(Reader reader)

参数:

**InputStream inStream:**字节输入流,不能读取含有中文的键值对

**Reader reader:**字符输入流,能读取包含中文的键值对

使用步骤:

1、创建Properties集合对象

2、使用Properties集合对象中的方法load读取保存键值对的文件

3、遍历Properties集合

注意:

1、存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)

2、存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取

3、存储键值对的文件中,键与值默认都是字符串,不用再加引号

第七节:缓冲流

7.1 概述

缓冲流,也叫高效流,是对4个基本的FileXxx流的增强,所以也是4个流,按照数据类型分类:

  • 字节缓冲流:BufferedInputStream,BufferedOutputStream
  • 字符缓冲流:BufferedReader,BufferedWriter

缓冲流的基本原理,是在创建对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZSwqWpz-1611640905198)(图片/34.png)]

7.2 字节缓冲流
字节缓冲输出流

java.io.BufferedOutputStream extends OutputStream

构造方法

  • public BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,以将数据写入指定的底层输出流
  • public BufferedOutputStream(OutputStream out,int size):创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流

参数:

OutputStream out:字节输出流。我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率

int size:指定缓冲流内部缓冲区的大小,不指定则默认

使用步骤:

1、创建一个FileOutputStream对象,构造方法中绑定要输出的目的地

2、创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率

3、使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中

4、使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据刷新到文件中

5、释放资源(会先调用flush方法刷新数据,第4步可省略)

public class BufferedOutputStream_Creat {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos=new FileOutputStream("D:\\Java\\CG\\a.txt");
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        bos.write("你好妈麻马骂麻麻".getBytes(StandardCharsets.UTF_8));
        bos.flush();
        bos.close();
    }
}
字节缓冲输入流

java.io.BufferedInputStream extendsInputStream

构造方法:

  • public BufferedInputStream(InputStream in):创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用
  • public BufferedInputStream(InputStream in,int size)创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流

参数:

**InputStream in:**字节输入流。我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率

**int size:**指定缓冲流内部缓冲区的大小,不指定则默认

使用步骤:

1、创建一个FileInputStream对象,构造方法中绑定要输出的目的地

2、创建BufferedInputStream对象,构造方法中传递FileOutputStream对象,提高FileInputStream对象效率

3、使用BufferedInputStream对象中的方法read,读取文件

4、释放资源

public class BufferedInputStream_Creat {
    public static void main(String[] args) throws IOException {
        FileInputStream fis=new FileInputStream("D:\\Java\\CG\\a.txt");
        BufferedInputStream bis=new BufferedInputStream(fis);
        byte[] bytes=new byte[1024];
        int len=0;
        while ((len=bis.read(bytes))!=-1)
            System.out.println(new String(bytes,0,len));
        bis.close();
    }
}
7.3 字符缓冲流
字符缓冲输出流

java.io.BufferedWriter extends Writer

构造方法:

  • public BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符流
  • public BufferedWriter(Writer out,int size):创建一个使用给定大小输出缓冲区的新缓冲字符输出流

参数:

**Writer out:**字符输出流。我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率

**int size:**指定缓冲区的大小,不写默认大小

特有的成员方法:

  • public void newLine():写出一个行分隔符,由系统属性定义符号。根据不同的操作系统写出不同的行分隔符

使用步骤:

1、创建字符缓冲输出流对象,构造方法中传递字符输出流

2、调用字符缓冲输出流的方法write,把数据写入到内存缓冲区中

3、调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中

4、释放资源

public class BufferedWriter_Creat {
    public static void main(String[] args) throws IOException {
        BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\Java\\CG\\a" +
                ".txt"));
        for (int i = 0; i <10 ; i++) {
            bw.write("你好你好");
            bw.newLine();
        }
        bw.flush();
        bw.close();
    }
}
字符缓冲输入流

java.io.BufferedReader extends Reader

构造方法:

  • public BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流
  • public BufferedReader(Reader in,int size):创建一个使用指定大小输入缓冲区的缓冲字符输入流

参数:

**Reader in:**字符输入流。我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的写入效率

**int size:**指定缓冲区的大小,不写默认大小

特有的成员方法:

  • public String readLine():读一行数据

行的终止符号:

换行:\n 回车:\r 或者 回车后直接跟着换行(\r\n)

返回值:包含该行内容的字符串,不包含任何终止符,如果已经到达流末尾,则返回null

使用步骤:

1、创建字符缓冲输入流对象,构造方法中传递字符输入流

2、调用字符缓冲输入流的方法read/readLine,读取文本

3、释放资源

public class BufferedReader_Creat {
    public static void main(String[] args) throws IOException {
        BufferedReader brd=new BufferedReader(new FileReader("D:\\Java\\CG\\a" +
                ".txt"));
        String s;
        while((s=brd.readLine())!=null)
            System.out.println(s);
        brd.close();
    }

第八节:转换流

8.1 字符编码和字符集

字符编码:

计算机中存储的信息都是用二进制表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符都是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象

**编码:**字符(能看懂的)—>字节(看不懂的)

**解码:**字节(看不懂的)---->字符(能看懂的)

  • 字符编码Character Encoding:就是一套自然语言的字符与二进制数之间的对应规则。

    编码表:生活中文字和计算机中二进制的对应规则

字符集:

  • 字符集Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

计算机要准确存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见的字符集有ACCII字符集、GBK字符集、Unicode字符集等

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ilw8ndEa-1611640905201)(图片/36.png)]

8.2 编码引出的问题

在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,默认都是UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码

8.3 转换流的原理

InputStreamReader原理图:

在这里插入图片描述

OutputStreamWriter原理图:
在这里插入图片描述

8.4 OutputStreamWriter类

java.io.OutputStreamWriter extends Writer

OutputStreamWriter字符流通向字节流的桥梁,可使用指定的charset 将要写入流中的字符编码成字节。(编码)它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

构造方法:

  • OutputStreamWriter(OutputStream out):创建使用默认编码集的OutputStreamWriter
  • OutputStreamWriter(OutputStream out,String charsetName):创建使用指定编码集的OutputStreamWriter

参数:

OutputStream out:字节输出流,可以用来写转换之后的字节到文件中

String charsetName:指定的编码表名称,可以是utf-8/UTF-8,gbk/GBK,…不指定默认使用UTF-8

使用步骤:

1、创建一个OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称

2、使用OutputStreamWriter对象中的方法write,把字符转换为字节存储存储到缓冲区中(编码)

3、使用OutputStreamWriter对象中的方法flush,把内存缓冲区的字节刷新到文件中(使用字节流写字节的过程)

4、释放资源

8.5 InputStreamReader类

转换流java.io.InputStreamReader ,是Reader的子类,是从字节流通向字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符(解码)。它的字符集可以由名称指定,也可以接受平台的默认字符集

构造方法:

  • InputStreamReader(InputStream in):创建一个使用默认字符集的字节流
  • InputStreamReader(InputStream in,String charsetName):创建一个指定字符集的字符流

参数:

InputStream in:字节输入流,用来读取文件中保存的字节

String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,…不指定默认使用UTF-8

使用步骤:

1、创建一个InputStreamWriter对象,构造方法中传递字节输入流和指定的编码表名称

2、使用InputStreamWriter对象中的方法read,读取文件

3、释放资源

**注意:**构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码

public class OutputStreamWriter_Creat {
    public static void main(String[] args) throws IOException {
        FileOutputStream fps=new FileOutputStream("D:\\Java\\CG\\d.txt");
        OutputStreamWriter osw=new OutputStreamWriter(fps,"GBK");
        osw.write("你好!");
        osw.flush();
        FileInputStream fis=new FileInputStream("D:\\Java\\CG\\d.txt");
        InputStreamReader isr=new InputStreamReader(fis,"GBK");
        char[] chars=new char[10];
        int s=0;
        while((s=isr.read(chars))!=-1)
            System.out.println(new String(chars,0,s));
        isr.close();
        osw.close();
    }
}

第九节: 序列化流

9.1 概述

**对象的序列化:**把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化

对象中包含的不仅仅是字符,所以使用字节流

ObjectOutputStream:对象的序列化流

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

读取的文件保存的都是字节,使用字节流

ObjectInputStream:对象的反序列化流

注意:

序列化和反序列化的时候,会抛出NotSerializableException没有序列化异常,类通过实现java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。

Serializable接口也叫做标记型接口,要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记,当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记,如果有:可以序列化和反序列化 如果没有:就会抛出NotSerializableException没有序列化异常

9.2 ObjectOutputStream类

java.io.ObjectOutputStream extends OutputStream类,将Java对象的原始数据类型写出到文件,实现对象的持久存储

构造方法:
  • public ObjectOutputStream(OutputStream out):创建写入指定OutputStreamObjectOutputStream

参数:

ObjectOutputStream out:字节输出流

特有的成员方法:

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

使用步骤:

1、创建ObjectOutputStream对象,构造方法中传递字节输出流

2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中

3、释放资源

public class ObjectOutputStream_Creat {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\Java\\CG\\a.txt"));
        oos.writeObject(new Person("张三",18));
        oos.close();
    }
}
9.3 ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectInputStream序列化的原始数据恢复为对象

java.io.ObjectInputStream extends InputStream

**作用:**把文件中保存的对象,以流的方式读取出来使用

构造方法:

  • public ObjectInputStream(InputStream in):创建一个指定InputStreamObjectInputStream

参数:

InputStream in:字节输入流

特有的成员方法:

public Object readObject():从ObjectInputStream读取对象

使用步骤:

1、创建ObjectInputStream对象,构造方法中传递字节输入流

2、使用ObjectInputStream对象中的方法readObject读取保存对象的文件

3、释放资源

4、使用读取出来的对象

反序列化的前提:

1、类必须实现Serializable接口

2、必须存在对应的class文件

public class ObjectInputStream_Creat {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\Java\\CG\\a.txt"));
        Object one=ois.readObject();
        ois.close();
        System.out.println(one);
    }
}
9.4 瞬态关键字 transient

static关键字:静态关键字

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

被static修饰的成员变量不能被序列化的,序列化的都是对象

transient关键字:瞬态关键字

被transient修饰的成员变量,不能被序列化

private transient int age;//age输出为0
9.5 InvalidClassException异常

当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法

Serializable接口给需要序列化的类提供了一个序列版本号。serialVersionUID该版本号的目的用于验证序列化的对象和对应类是否版本匹配

异常原理图:

异常原理图

解决方案:

序列化类可以通过声明为serialVersionUID的字段(该字段必须是静态(static)、最终(final)的long型字段),显式声明自己的serialVersionUID

private static final long serialVersionUID=1L;

第十节:打印流

10.1 概述

平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式

10.2 PrintStream类

PrintStream extends OutputStream

特点:

1、只负责数据的输出,不负责数据的读取

2、与其他输出流不同,PrintStream永远不会抛出IOException

3、有特有的方法,print,println

  • public void print(任意类型的值)
  • public void println(任意类型的值并换行)

构造方法:

  • public PrintStream(File file):输出的目的地是一个文件

  • public PrintStream(OutputStream out):输出的目的地是一个字节输出流

  • public PrintStream(String fileName):输出的目的地是一个文件路径

**注意:**如果使用继承来自父类的write方法写数据,那么查看数据的时候会查询编码表 97–>a

​ 如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97—>97

public class PrintStream_Creat {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps=new PrintStream("D:\\Java\\CG\\e.txt");
        ps.write(97);
        ps.print(97);
        ps.print(97);
        ps.println(97);
        ps.println(97);
        ps.close();
    }
}
a979797
97

改变输出语句的目的地(打印流的流向)

输出语句默认在控制台上输出

使用System.setOut(PrintStream out)方法改变输出语句的目的地改为参数中传递的打印流的目的地

public class PrintStream_setOut {
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("我在控制台输出");

        PrintStream out=System.out;//保存最原始的输出流
        PrintStream ps=new PrintStream("D:\\Java\\CG\\目的地是打印流.txt");
        System.setOut(ps);
        System.out.println("我在打印流的目的地输出");
        System.setOut(out);
        System.out.println("我又恢复在控制台上打印");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值