JAVA IO流

JAVA IO流

1. File

1.1 File 类概述和构造方法

File:它是文件和目录路径名的抽象表示

  • 文件和目录是可以通过 File 封装成对象的
  • 对于 File 而言,其封装的并不是一个正真的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的
方法名说明
File ( String pathname )通过将给定的路径名字转换为抽象路径名来创建新的 File 实例
File ( String parent, String child )从父路径名字符串和子路径名字符串创建新的 File 实例
File ( File parent, String child )从父抽象路径名和子路径名字符串创建新的 File 实例

1.2 File 类创建功能

方法名说明
public boolean createNewFile ( )当具有该名称的文件不存在时,创建一个有该抽象路径命名的新空文件
public boolean mkdir ( )创建由此抽象路径命名的目录
public boolean mkdirs ( )创建由此抽象路径命名的目录,包括任何必须但不存在的父目录(多级目录)

1.3 File 类删除功能

方法名说明
public boolean delete ( )删除由此抽象路径名表示的文件或目录

绝对路径和相对路径的区别

  • 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如: E:\FileDemo\JavaSE.txt
  • 相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\Java.txt

删除目录时的注意事项

  • 如果一个目录中有内容(目录,文件),不能直接删除。应该先删除目录中的内容,最后才能删除目录

1.4 File 类判断和获取功能

方法名说明
public boolean isDirectory ( )测试此抽象路径名表示的 File 是否为目录
public boolean isFile ( )测试此抽象路径名表示的 File 是否为文件
public boolean exists ( )测试此抽象路径名表示的 File 是否存在
public String getAbsolutePath ( )返回此抽象路径名的绝对路径名字符串
public String getPath ( )将此抽象路径名转换为路径名字符串
public String getName ( )返回由此抽象路径名表示的文件或目录的名称
public String[] list ( )返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] isFiles ( )返回此抽象路径名表示的目录中的文件和目录的 File 对象数组

1.5 递归

递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象

递归解决问题的思路:

把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算

递归解决问题要找到两个内容:

  • 递归出口:否则会出现内存溢出
  • 递归规则:与原问题像是的规模较小的问题

2. 字节流

2.1 IO流概述和分类

IO流概述:

  • IO:输入 / 输出(Input / Output)
  • 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备键的传输称为流,流的本质是数据传输
  • IO流就是用来处理设备键数据传输问题的
    • 常见的应用:文件复制;文件上传;文件下载

IO流分类:

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

一般来说,我们说IO流的分类是按照数据类型来分的

使用场景

  • 如果数据通过 Window 自带的记事本软件打开,我们还可以读懂里面的内容 ,就是用字符流,否则使用字节流。如果不知道该使用哪种类型的流,就使用字节流(万能流)

2.2 字节流写数据

字节流抽象基类

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

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

  • FileOutputStream ( String name ): 创建文件输出流以指定的名称写入文件

使用字节输出流写数据的步骤:

  • 创建字节输出流对象(a:调用系统功能创建了文件,b:创建字节输出流对象,c:让字节输出流对象指向文件)
  • 调用字节输出流对象的写数据方法
  • 释放资源(a:关闭此文件输出流,b:释放与此流相关联的任何系统资源)

2.3 字节流写数据的3种方式

方法名说明
void write ( int b )将指定的字节写入此文件输出流
一次写一个字节数据
void write ( byte[] b )b.length 字节从指定的字节数组写入此文件输出流
一次写一个字节数组数据
void write ( byte[] b, int off, int len )将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
一次写一个字节数组的部分数据

2.4 字节流写数据的两个小问题

字节流写数据如何实现换行呢?

  • 写完数据后,加换行符
    • Windows: \r \n
    • Linux: \n
    • Mac: \r

字节流写数据如何实现追加写入呢?

  • public FileOutputStream(String name,boolean append)
  • 创建文件输出流以写入具有指定名称的文件。如果第二个参数是true ,则字节将写入文件的末尾而不是开头

2.5 字节流写数据加异常处理

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

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

	try {
        可能出现异常的代码;
    } catch (异常类名 变量名) {
        异常的处理代码;
    } finally {
        执行所有清除操作;
    }
    //try加入finally来实现释放资源
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream("myByteStream\\fos.txt");
        fos.write("Hello".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2.6 字节流读数据(一次读一个字节数据)

需求:把文件 fos.txt 中的内容读取出来在控制台输出

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

  • FileInputStream(String name):通过打开与实际文件的连接来创建一个 FileInputStream,该文件有文件系统中的路径名 name 命名

使用字节输入流读数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
//字节流读数据标准格式)
int by;
/*
    fis.read():读数据
    by = fis.read():把读到的数据赋值给by
    by != -1:判断读取到的数据释放是-1
 */
while ((by = fis.read()) != -1) {
    System.out.print((char) by);
}

2.6 字节流读数据(一次读一个字节组数据)

需求:把文件 fos.txt 中的内容读取出来再控制台输出

使用字节输入流读取数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读取方法
  3. 释放资源
byte[] bys = new byte[1024]; //1024及其整数倍

int len;
while ((len = fis.read(bys)) != -1) {
    System.out.println(new String(bys, 0, len));
}

2.7 字节缓冲流

字节缓冲流:

  • BufferOutputStream :该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream :创建 BufferedInputStream 将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将更具需要从所包含的输入流中重新填充,一次很多字节

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStream)
  • 字节缓冲输入流:BufferedInputStream(InputStream in)

为什么构造方法需要的时字节流,而不是具体的文件或者路径呢?

  • 字节缓冲流仅仅提供缓冲区,而正真的读写数据还得依靠基本的字节流对象进行操作

3. 字符流

3.1 为什么会出现字符流

由于字节流操作中文补充特别的方便,所以Java就提供字符流

  • 字符流 = 字节流 + 编码表

用字节流复制文本文件时,文本文件中也会有中午,但是没有问题,原因是最终底层操作会自动进行字节拼接成中午,如何识别是中午呢?

  • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

3.2 编码表

基础知识:

  • 计算机中储存的信息都是用二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
  • 按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制按照某种规则解析显示出来,称为解码。这里强调一下:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象
    • 字符编码:就是一套自然语言的字符与二进制数之间的对应规则 E:(A, 65)

字符集:

  • 是一个系统支持的所有字符的集合,包括各个国家文字、标点符号、图形符号、数字等

  • 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。

    常见的字符集有 ASCII 字符集、GBXXX 字符集、 Unicode 字符集等

ASCII字符集:

  • ASCII(American Standard COde for Information Interchange, 美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示现代应用,主要包括控制字符(回车、退格、换行等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
  • 基本的 ASCII 字符集,使用 7 为表示一个字符,共 128 字符。ASCII 的扩展字符集使用 8 为表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

GBXXX字符集:

  • GB2312:简体中文码表。一个小于 127 的字符的意义与原来相同,但两个大于 127 的字符连在一起时,就表示一个汉字,这样大于可以组合了包括 7000 多个简体汉字,此外数学符号、罗马希腊的字符、日文的假名等都编进去了,连在 ASCII 里本来就有的数组、标点、字母都统统重新编了两个字节长的编码,这就是常说的 “全角” 字符,而原来在 127 号一下的那些就叫 ”半角“ 字符了
  • GBK:最常用的中文码表。是在 GB2312 标准基础上的扩展规范,使用了双字节编码方案,共收录了 21003 个汉字,完全兼容 GB2312 标准,同时支持繁体汉字以及日韩汉字等
  • GB18030:最新的中文码表。收录汉字 70244 个,采用多字节编码,每个字可以由1个、2个或者4个字节组成。支持中国国内少数名族的文字,同时支持繁体汉字以及日韩汉字等

Unicode字符集:

  • 为表达任意语言的任意字符而设计,是业界的一种标准,也成为统一码、标准万国码。它最多使用 4 个字节的数字来表达每个字母、符号、或者文字。由三种编码方案,UTF-8UTF-16UTF32。最常用的是 UTF-8 编码

  • UTF-8 编码:可以用来表示 Unicode 标准中人称字符、它是电子邮件、网页及其他存储或传输文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持 UTF-8 编码。它使用一至四个字节为每个字符编码

    编码规则:

    ​ 128个US-ASCII字符,只需要一个字节编码

    ​ 拉丁文等字符,需要二个字节编码

    ​ 大部分常用字(含中文),使用三个字节编码

    ​ 其他极少数使用的 Unicode 辅助字符,使用四字节编码

小结:采用何种规则编码,就要采用对应规则解码,否则就会出现乱码


3.3 字符串中的编码解码问题

编码:

  • byte[] getBytes():使用平台的默认字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
  • byte[] getBytes( String charsetName ):使用指定的字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中

解码:

  • String(byte[] bytes):通过使用平台的默认字符集解析指定的字节数组来构建新的 String
  • String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String

3.4 字符流中的编码解码问题

字符流抽象基类

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

字符流中的编码解码问题相关的两个类

  • InputStreamReader

    InputStreamReader是从字节流到字符流的桥接器:

    它使用指定的charset读取字节并将其解码为字符。

    它使用的字符集可以通过名称指定,也可以明确指定,或者可以接受平台的默认字符集。

  • OutputStreamWriter

    OutputStreamWriter是从字符流到字节流的桥接器:

    使用指定的charset写入其中的字符编码为字节。

    它使用的字符集可以通过名称指定,也可以明确指定,或者可以接受平台的默认字符集。


3.5 字符流写入数据5种方式

方法名说明
void 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 )写一个字符串的一部分
方法名说明
flush()刷新流,还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

3.6 字符流读数据的2种方式

方法名说明
int read()一次读一个字符数据
int read(char[] cbuf)一次读一个字符数组数据

3.7 字符缓冲流

字符缓冲流:

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

构造方法:

  • BufferedWriter(Writer out)
  • BufferedReader(Reader in)

3.8 字符缓冲流特有功能

BufferedWriter

  • void newLine():写一行分隔符,行分隔符字符串由系统属性定义

BufferedReader

  • public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾以及到达,则为null

3.9 IO流小结

字节输入流InputStream

读数据

  • int read():一次读取一个字节
  • int read(byte[] bys):一次读取一个字节数组

实现类

  • FileInputStream
  • BufferedInputStream

字节输出流OutputStream

写数据

  • void write(int by):一次写一个字节
  • void write(byte[] bys, int index, int len):一次写一个字节数组的一部分

实现类

  • FileOutputStream
  • BufferedOutputStream

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mgSGwLRY-1609673670753)(https://s3.ax1x.com/2020/12/28/rT5yk9.png)]

小结:字节流可以复制任意文件数据,有4种方法一般采用字节缓冲流一次读写一个字节数组的方式


字符输入流Reader

读数据

  • int read():一次读取一个字符
  • int read(char[] chs):一次读取一个字符数组

实现类

  • InputStreamReader

    子类:FileReader

  • BufferedReader

    特殊方法:

    String readLine():一次读取一个字符串

字符输出流Writer

写数据

  • void write(int ch):一次写一个字符
  • void write(char[] chs, int index, int len):一次写一个字符数组的一部分

实现类

  • OutputStreamWriter

    子类:FileWriter

  • BufferedWriter

    特殊方法:

    void newLine():写一个换行符

    void write(String line):一次写一个字符串

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CLytcocV-1609673670755)(https://s3.ax1x.com/2020/12/28/rTooRI.png)]

小结:字符流只能复制文本数据,有5种方式,一般采用字符缓冲流的特有功能


3.10 复制文件的异常处理

try . . .catch . . .finally 的做法:

	try {
        可能出现异常的代码;
    }catch(异常类名 变量名){
        异常的处理代码;
    }finally{
        执行所有的清除操作;
    }

JDK7改进方案

	try(定义流对象) {
        可能出现异常的代码;
    } catch(异常名 变量名) {
        异常的处理代码;
    }
	
	**自动释放资源**

JDK9 改进方案

	定义输入流对象:
	定义输出流对象:
	try(输入流对象; 输出流对象) {
        可能出现异常的代码;
    }cath(异常类名 变量名) {
        异常的处理代码;
    }

	**自动释放资源**

4. 特殊操作流

4.1 标准输入输出流

方法名成员变量描述
static PrintStreamerr"标准"错误输出流
static InputStreamin"标准"输入流
static PrintStreamout"标准"输出流

System类中由两个静态的成员变量:

  • public static final InputStream in

    "标准"输入流,该流已经打开,准备提供输入数据。通常,该流对应于键盘输入或有主机环境或用户指定的另一个输入源

  • public static final PrintStream out

    "标准"输出流。此流已经打开并准备号接收数据。通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。

自己实现键盘录入数据:

  • BufferedReadedr br = new BufferedReader(new InputStreamReader(System.in));

写起来太麻烦,Java提供了Scanner实现键盘录入

  • Scanner sc = new Scanner(System.in);

输出语句的本质: 是一个标准的输出流

  • PrintStream ps = System.out;
  • PrintStream类有的方法,System.out都可以使用

4.2 打印流

打印流分类:

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

打印流的特点:

  • 只负责输出数据,不负责读取数据
  • 有自己的特有方法

字节打印流

  • PrintStream(String fileName):使用指定的文件名创建新的打印流
  • 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出

字符打印流PrintWriter的构造方法:

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

4.3 对象序列化流

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

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

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

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

要实现序列化和反序列化就要使用对象序列化流对象反序列化流

  • 对象序列化流:ObjectOutputStream
  • 对象反序列化流:ObjectInputStream

对象序列化流:ObjectOutputStream

  • 将Java对象的原始数据类型和图像写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果是网络套接字流,则可以在另一个主机上或另一个进程中重构对象

构造方法:

  • ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStreamObjectOutputStream

序列化对象的方法:

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

    注意:

  • 一个对象要想被序列化,该对象所属的类必须实现 Serizlizable 接口

  • Serializable 是一个标记接口,实现该类,不需要重写任何方法


对象反序列化流ObjectInputStream

  • ObjectInputStream 反序列化先前使用 ObjectOutputStream 编写的原始数据和对象

构造方法:

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

反序列化对象的方法:

  • ObjectreadObject():从 ObjectInputStream 读取一个对象

用对象序列化六序列化了一个对象后,加入我们修改了的中心所属的类文件,读取数据会不会出问题呢?

  • 会出问题,抛出 InvalidClassException 异常

如果出问题了,如何解决呢?

  • 给对象所属的类加一个 serialVersionUID

    private static final long serialVersionUID = 42L;

如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?

  • 给该成员变量加 transient 关键字修饰,该关键字标记的成员变量不参与序列化过程

4.4 Properties

Properties 概述:

  • 是一个 Map 体系的集合类
  • Properties 可以保存到流中或从流中加载

Properties 作为集合的特有方法:

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

PropertiesIO 流结合的方法:

方法名说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)将此属性列表(将和元素对)写入此Properties 表中,以适合于使用 load(InputStream) 方法的格式写入输出字节流
void store(Writer writer, String comments)将此属性列表(将和元素对)写入此Properties 表中,以适合于使用 load(Reader) 方法的格式写入输出字节流
| 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |

PropertiesIO 流结合的方法:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值