File与IO

132 阅读8分钟

File与IO

File类位于java.io包下,本章中涉及到的相关流也都声明在java.io包下。

1. File类的理解及使用

File类的一个对象,对应与操作系统下的一个文件或一个文件目录(或文件夹)

File类中声明了新建、删除、获取名称、重命名等方法,并没有涉及到文件内容的读写操作。要想实现文件内容的读写,我们就需要使用io流。

File类的对象,通常是作为io流操作的文件的端点出现的。

代码层面,将File类的对象作为参数传递到IO流相关类的构造器中。

构造器

public File(String pathname):以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。

public File(String parent, String child):以parent为父路径,child为子路径创建File对象。

public File(File parent, String child):根据一个父File对象和子文件路径创建File对象

方法

获取文件和目录基本信息

  • public String getName() :获取名称
  • public String getPath() :获取路径
  • public String getAbsolutePath():获取绝对路径
  • public File getAbsoluteFile():获取绝对路径表示的文件
  • public String getParent():获取上层文件目录路径。若无,返回null
  • public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
  • public long lastModified() :获取最后一次的修改时间,毫秒值

列出目录的下一级

  • public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
  • public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。

File类的重命名功能

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径。

判断功能的方法

  • public boolean exists() :此File表示的文件或目录是否实际存在。
  • public boolean isDirectory() :此File表示的是否为目录。
  • public boolean isFile() :此File表示的是否为文件。
  • public boolean canRead() :判断是否可读
  • public boolean canWrite() :判断是否可写
  • public boolean isHidden() :判断是否隐藏

创建、删除功能

  • public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false。

  • public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。

  • public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建。

  • public boolean delete() :删除文件或者文件夹

删除注意事项:① Java中的删除不走回收站。② 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。

其他注意:

绝对路径:以windows操作系统为例,包括盘符在内的文件或文件目录的完整路径。

相对路径:相对于某一个文件目录来讲的相对的位置。

  • 在IDEA中,如果使用单元测试方法:相对于当前的module来讲
  • 如果使用main()方法:相对于当前的project来讲

2. IO流的概述

  • IO流的分类
    • 流向:输入流、输出流
    • 处理数据单位:字节流、字符流
    • 流的角色:节点流、处理流
  • IO的4个抽象基类:InputStream \ OutputStream \ Reader \ Writer

3. 节点流之:文件流

  • FileInputStream \ FileOutputStream \ FileReader \ FileWriter

FileReader \ FileWriter 的使用

  • 读写数据的过程。
    • 步骤1:创建File类的对象,作为读取或写出数据的端点
    • 步骤2:创建相关的流的对象
    • 步骤3:具体的读入或写出的过程。
      • 读入:read(char[] cbuffer)
      • 写出:write(String str) / write(char[] cbuffer,0,len)
    • 步骤4:关闭流资源,避免内存泄漏

注意点

  • ① 因为涉及到流资源的关闭操作,所以出现异常的话,需要使用try-catch-finally的方式来处理异常
  • ② 对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则,会报FileNotFoundException
    • 对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。
      • 如果此文件不存在,则在输出的过程中,会自动创建此文件,并写出数据到此文件中。
      • 如果此文件存在,使用 FileWriter(File file)FileWriter(File file,false): 输出数据过程中,会新建同名的文件对现有的文件进行覆盖。FileWriter(File file,true) : 输出数据过程中,会在现有的文件的末尾追加写出内容。

FileInputStream \ FileOutputStream 的使用

  • 读写数据的过程:
    • 步骤1:创建读取或写出的File类的对象
    • 步骤2:创建输入流或输出流
    • 步骤3:具体的读入或写出的过程。
      • 读入:read(byte[] buffer)
      • 写出:write(byte[] buffer,0,len)
    • 步骤4:关闭流资源,避免内存泄漏

注意点:

在以上的注意点的基础之上,看其他的注意点。

对于字符流,只能用来操作文本文件,不能用来处理非文本文件的。

对于字节流,通常是用来处理非文本文件的。但是,如果涉及到文本文件的复制操作,也可以使用字节流。

文本文件:.txt 、.java 、.c、.cpp、.py等

非文本文件:.doc、.xls 、.jpg 、.pdf、.mp3、.mp4、.avi 等

4. 处理流之一:缓冲流

  • BufferedInputStream \ BufferedOutputStream \ BufferedReader \ BufferedWriter
  • 作用:实现更高效的读写数据的操作,提升文件读写的效率

实现的步骤

  • 第1步:创建File的对象、流的对象(包括文件流、缓冲流)
  • 第2步:使用缓冲流实现 读取数据写出数据的过程(重点)
    • 读取:int read(char[] cbuf/byte[] buffer) :
      • 每次将数据读入到cbuf/buffer数组中,并返回读入到数组中的字符的个数
    • 写出:void write(String str)/write(char[] cbuf):
      • 将str或cbuf写出到文件中
      • void write(byte[] buffer) 将byte[]写出到文件中
  • 第3步:关闭资源

4个缓冲流使用的方法:

处理非文本文件的字节流:

BufferedInputStream ---> read(byte[] buffer)

BufferedOutputStream ---> write(byte[] buffer,0,len) 、flush()

处理文本文件的字符流:

BufferedReader ---> read(char[] cBuffer) / String readLine()

BufferedWriter ---> write(char[] cBuffer,0,len) / write(String ) 、flush()

5. 处理流之二:转换流

作用:

实现字节与字符之间的转换

API:

  • InputStreamReader: 将一个输入型的字节流转换为输入型的字符流。
  • OutputStreamWriter: 将一个输出型的字符流转换为输出型的字节流。

ascii:主要用来存储a、b、c等英文字符和1、2、3、常用的标点符号。每个字符占用1个字节。

iso-8859-1:了解,每个字符占用1个字节。向下兼容ascii。

gbk:用来存储中文简体繁体、a、b、c等英文字符和1、2、3、常用的标点符号等字符。中文字符使用2个字节存储的。向下兼容ascii,意味着英文字符、1、2、3、标点符号仍使用1个字节。

utf-8:可以用来存储世界范围内主要的语言的所有的字符。使用1-4个不等的字节表示一个字符。中文字符使用3个字节存储的。向下兼容ascii,意味着英文字符、1、2、3、标点符号仍使用1个字节。

6. 处理流之三:对象流

数据流及其作用

DataOutputStream:可以将内存中的基本数据类型的变量、String类型的变量写出到具体的文件中。 DataInputStream:将文件中保存的数据还原为内存中的基本数据类型的变量、String类型的变量。

对象流及其作用

作用:

可以读写基本数据类型的变量、引用数据类型的变量。

API:

ObjectInputSteam ObjectOutputStream

对象的序列化机制是什么

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上, 或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。

例如

序列化过程:使用ObjectOutputStream流实现。将内存中的Java对象保存在文件中或通过网络传输出去

反序列化过程:使用ObjectInputSteam流实现。将文件中的数据或网络传输过来的数据还原为内存中的Java对象

自定义类要想实现序列化机制,需要满足:

  • ① 自定义类需要实现接口:Serializable
  • ② 要求自定义类声明一个全局常量:
    • static final long serialVersionUID = 42234234L; //用来唯一的标识当前的类。
  • ③ 要求自定义类的各个属性也必须是可序列化的。
    • 对于基本数据类型的属性:默认就是可以序列化的
    • 对于引用数据类型的属性:要求实现Serializable接口

注意点:

  • ① 如果不声明全局常量serialVersionUID,系统会自动声明生成一个针对于当前类的serialVersionUID。
    • 如果修改此类的话,会导致serialVersionUID变化,进而导致反序列化时,出现InvalidClassException异常。
  • ② 类中的属性如果声明为transient或static,则不会实现序列化。

7. 其它流的使用

标准输入、输出流

  • System.in: 标准的输入流,默认从键盘输入
  • System.out:标准的输出流,默认从显示器输出(理解为控制台输出)

通过调用如下的方法,修改输入流和输出流的位置

  • setIn(InputStream is)
  • setOut(PrintStream ps)

数据流:

  • DataInputStream
  • DataOutputStream

打印流:

  • PrintStream
  • PrintWriter