前言
File与IO流的功能完全可以用Java中的Files或者是apache开源基金组织提供的Commons-io框架。Commons-io的功能比Files强大,但框架需要到开发这些框架的公司官网上去下载。而且这些内容都是基与File与IO流开发出来的,学习File与IO流有助于理解其源代码。
File与IO流概述
File
File是java.io.包下的类, File类的对象, 用于代表当前操作系统的文件(可以是文件、或文件夹)。
主要功能是对文件夹的操作比如:获取文件信息(大小,文件名,修改时间)、创建文件/文件夹、删除文件/文件夹、判断文件的类型等。(File类只能对文件本身进行操作,不能读写文件里面存储的数据。)
IO流
●用于读写数据的(可以读写文件,或网络中的数据...)
File
创建File对象
构造方法
构造器 | 说明 |
public File(String pathname ) | 根据文件路径创建文件对象 |
public File(String parent, String child) | 根据父路径和子路径名字创建文件对象 |
public File(File parent, String child) | 根据父路径对应文件对象和子路径名字创建文件对象 |
补充
- 带盘符的是绝对路径,不带盘符的为相对路径(默认是直接去工程下寻找文件的,以项目名开始写路径)。
- 路径分割符可以用 / 或 \\ 。
- File可以指代一个不存在的文件路径(可以用File创建文件)
- 要定位的文件是在模块中可以使用相对路径。
- 在写入路径时Java会报错以防路径错误,可以直接抛出错误。(用throws Exception)
常用方法
判断文件类型、获取文件信息
方法名称 | 说明 |
public boolean exists() | 判断当前文件对象,对应的文件路径是否存在,存在返回true |
public boolean isFile() | 判断当前文件对象指代的是否是文件,是文件返回true,反之。 |
public boolean isDirectory() | 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。 |
public String getName() | 获取文件的名称(包含后缀) |
public long length() | 获取文件的大小,返回字节个数 |
public long lastModified( ) | 获取文件的最后修改时间。 |
public String getPath() | 获取创建文件对象时,使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
创建与删除文件
方法名称 | 说明 |
public boolean createNewFile() | 创建一个新文件(文件内容为空),创建成功返回true,反之。 |
public boolean mkdir() | 用于创建文件夹,(只能创建一级 文件夹) |
public boolean mkdirs() | 用于创建文件夹,(可以创建多级文件夹) |
public boolean delete() | 删除文件,或者空文件,(不能删除非空文件夹) |
delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。
遍历文件夹
方法名称 | 说明 |
public String[] list() | 获取当前目录下所有的 “一级文件和文件夹名称 ” 到一 个字符串数组中去返回。 |
public File[] listFiles() | 获取当前目录下所有的 “ 一级文件对象 ” 到一个文件对象数组中去返回。 |
使用listFiles方法时的注意事项:
- 当主调是文件, 或者路径不存在时,返回null。
- 当主调是空文件夹时, 返回一个长度为0的数组。
- 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回。
- 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件。
- 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null。
IO流
简介
- IO流中I指Input,称为输入流:负责把数据读到内存中去
- IO流中O指Output,称为输出流:负责写数据出去
IO流分类
分类方式 | 说明 | |
流的方向 | 输入流 | |
输出流 | ||
流中数据的最小单位 | 字节流 | 适合操作所有类型的文件 |
字符流 | 只适合操作纯文本文件 |
IO流总体来看就有四大流:字节输入流、字节输出流、字符输入流、和字符输出流。
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中的流。代表是InputStream(抽象类)实现类有FilelnputStream(Java.io包下)。
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中的流。代表是OutputStream(抽象类)实现类有FileOutputSteam(Java.io包下)。
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中的流。代表是Reader(抽象类)实现类有FileReader(Java.io包下)。
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中的流。代表是Writer(抽象类)实现类有FileWriter(Java.io包下)。
字节流
FileInputStream (文件字节输入流)
FileInputStream作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
构造器 | 说明 |
public FileInputStream(File file) | 创建字节输入流管道与源文件接通 |
public FileInputStream(String pathname) | 创建字节输入流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字节返回, 如果发现没有数据可读会返回-1。(每次读取一个字节, 读取性能较差,并且读取汉字输出会乱码。) |
public int read(byte[ ] buffer) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1。(也不能避免读取汉字输出乱码的问题) |
流使用完毕之后,必须关闭!释放系统资源!关闭流可以调用方法close()
一次读取完全部字节
方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。
方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。(Java1.9后才有!)
方法名称 | 说明 |
public byte[ ] readAllBytes() throws IOException | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
- 如果文件过大,创建的字节数组也会过大,可能引起内存溢出。
- 读'写文本内容更适合用字符流
- 字节流适合做数据的转移,如:文件复制等。
FileOutputStream(文件字节输出流)
FileOutputStream作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。(会自动创建文件)
构造器 | 说明 |
public File0utputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public File0utputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public File0utputStream(File file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
public void write(int a) | 写一个字节出去 |
public void write(byte[ ] buffer ) | 写一个字节数组出去 |
public void write(byte[ ] buffer,int pos ,int len) | 写一个字节数组的一部分出去。(包前不包后) |
public void close() throws IoException | 关闭流。 |
在要写的文本中换行时用 “ /r/n ” ,用 “ /n ”只能在Windows中换行 。
释放资源的方式
try-catch-finally
finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止。(即使有return结束方法也会执行finally后结束,所以在方法中返回数据时不要在finally里return不然无论如何返回的数据都是finally里的。)
作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。
try-with-resource
try-with-resource是JDK7之后才有的。
try后的小括号里定义的资源(小括号里也只能放置资源)在try结束时会自动调用close()方法来释放资源。
资源都是会实现AutoCloseable中接口,资源都会有一个close方法
字符流
适合读写文本文件内容
FileReader (文件字符输入流)
- 作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。
构造器 | 说明 |
public FileReader(File file) | 创建字符输入流管道与源文件接通 |
public FileReader(String pathname) | 创建字符输入流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字符返回, 如果发现没有数据可读会返回-1。 |
public int read( char[ ] buffer ) | 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果发现没有数据可读会返回-1。 |
FileWriter(文件字符输出流)
- 作用:以内存为基准,把内存中的数据以字符的形式写出到文件中去。
构造器 | 说明 |
public Filewriter(File file) | 创建字节输出流管道与源文件对象接通 |
public FileWriter(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileWriter(File file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileWriter(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
void write(int c) | 写一个字符 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分(包前不包后) |
void write(char[ ]cbuf) | 写入一个字符数组 |
void write(char[ ] cbuf, int off, int len) | 写入字符数组的一部分(包前不包后) |
字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效(文件字符输出流会先把输出的文字放到缓冲流中(当缓冲流中装满数据后会自动写入文本后再装入新的数据),当流刷新或关闭时才会写到文本中去,性能比较好)
刷新流的方法:flush()
流刷新后还可以继续使用。(关闭流,关闭流包含刷新操作!)
缓冲流
概述
字节缓冲流 | BufferedInputStream | 字节缓冲输入流 | InputStream下的实现类 |
Buffered0utputStream | 字节缓冲输出流 | OutputStream下的实现类 | |
字符缓冲流 | BufferedReader | 字符缓冲输入流 | Reader下的实现类 |
BufferedWriter | 字符缓冲输出流 | Writer下的实现类 |
- 缓冲流作用:对原始流进行包装,以提高原始流读写数据的性能。
- FileInputStream、FileOutputSteam、FileOutputSteam、FileReader、FileWriter被称为原始流/低级流
- BufferedInputStream、Buffered0utputStream、BufferedReader、BufferedWriter被称为包装流/处理流
字节缓冲流
- 字节缓冲流的作用:提高字节流读写数据的性能
- 原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池。
构造器 | 说明 |
public BufferedInputStream( InputStream is) | 把低级的字节输入流包装成一个高级的缓冲字节输入流 |
public Buffered0utputStream(0utputStream os) | 把低级的字节输 出流包装成一个高级的缓冲字节输出流 |
public BufferedInputStream( InputStream is,a) | 把低级的字节输入流包装成一个高级的缓冲字节输入流同时带a字节的缓冲池 |
public Buffered0utputStream(0utputStream os,a) | 把低级的字节输 出流包装成一个高级的缓冲字节输出流同时带a字节的缓冲池 |
字符缓冲流
BufferedReader(字符缓冲输入流)
●作用:自带8K (8192) 的字符缓冲池,可以提高字符输入流读取字符数据的性能。
构造器 | 说明 |
public BufferedReader(Reader r) | 把低级的字符输入流包装成字符缓冲输入流管道 ,从而提高字符输入流读字符数据的性能 |
字符缓冲输入流新增的功能:按照行读取字符
方法 | 说明 |
public String readLine() | 读取一 行数据返回,如果没有数据可读了,会返回null |
BufferedWriter(字符缓冲输出流)
●作用:自带8K的字符缓冲池,可以提高字符输出流写字符数据的性能。
构造器 | 说明 |
public BufferedWriter(Writer r) | 把低级的字符输出流包装成一 个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能 |
字符缓冲输出流新增的功能:换行
方法 | 说明 |
public void newLine( ) | 换行 |
原始流与缓冲流的性能分析
- 低级字节流一个一个字节的赋值,慢的简直让人无法忍受,直接淘汰!
- 低级的字节流流按照一个一个字节数组的形式复制,速度较慢!
- 缓冲流按照一个一个字节的形式复制,速度较慢,直接淘汰!
- 缓冲流按照一个 一个字节数组的形式复制,速度极快,推荐使用!
- 低级的字节流用的数组很大的情况下性能也很好,大而且还有可能比缓冲流的性能还好但是要占的内存很大。(相当于用内存换效率)
- 低级的字节流的字节数组大到一定程度时再增大数组的大小性能的差别也不会太大了。(缓冲流也一样)
转换流
如果代码编码和被读取的文本文件的编码是一致的, 使用字符流读取文本文件时不会出现乱码!但是如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
InputStreamReader ( 字符输入转换流)
- Reader下的实现类
- 解决不同编码时,字符流读取文本内容乱码的问题。
- 解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。
构造器 | 说明 |
public InputStreamReader(InputStream is) | 把原始的字节输入流,按照代码默认编码转成字符输入流(与直接用FileReader的效果一样) |
public InputStreamReader(InputStream is,String charset) | 把原始的字节输入流,按照指定字符集编码转成字符输入流(重点) |
OutputStreamWrite(字符输出转换流)
- Writer下的实现类
- 作用:可以控制写出去的字符使用什么字符集编码。
- 解决思路:获取字节输出流,再按照指定的字符集编码将其转换成字符输出流,以后写出去的字符就会用该字符集编码了。
构造器 | 说明 |
public OutputStreamWriter (0utputStream os ) | 可以把原始的字节输出流,按照代码默认编码转换成字符输出流。 |
public OutputStreamWriter(OutputStream os, String charset) | 可以把原始的字节输出流,按照指定编码转换成字符输出流(重点) |
也可调用String提供的getBytes方法解决
String data = "我爱你中国abc";
byte[] bytes = data.getBytes("GBK");
打印流
- 打印流有PrintStream和PrintWriter。
- 作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去。
- 不支持追加数据
PrintStream提供的打印数据的方案
构造器 | 说明 |
public PrintStream(OutputStream/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintStream(String fileName, Charset charset) | 可以指定写出去的字符编码 |
public PrintStream(OutputStream out, boolean autoFlush) | 可以指定实现自动刷新 |
public PrintStream(OutputStream out, boolean autoFlush, String encoding) | 可以指定实现自动刷新,并可指定字符的编码 |
方法 | 说明 |
public void println(Xxx xx) | 打印任意类型的数据出去(带ln会换行,不带ln就不换行) |
public void write(int/byte[ ]/byte[ ]一部分) | 可以支持写字节数据出去 |
PrintWriter提供的打印数据的方案
构造器 | 说明 |
public PrintWriter(OutputStream/Writer/File/string) | 打印流直接通向字节输出流/文件/文件路径 |
public PrintWriter(String fileName, Charset charset) | 可以指定写出去的字符编码 |
public PrintWriter(QutputStream out/Writer, boolean autoFlush) | 可以指定实现自动刷新 |
public Printwriter(QutputStream out, boolean autoFlush, String encoding) | 可以指定实现自动刷新,并可指定字符的编码 |
方法 | 说明 |
public void println(Xxx xx) | 打印任意类型的数据出去 |
pub1ic void write(int/String/char[ ]/..) | 可以支持写字符数据出去 |
PrintStream和PrintWriter的区别
- 打印数据的功能上是一模一样的:都是使用方便,性能高效(核心优势)
- PrintStream继承自字节输出流OutputStream,因此支持写字节数据的方法。
- PrintWriter继承自字符输出流Writer,因此支持写字符数据出去。
输出语句的重定向
输出语句的重定向是打印流的一种应用,可以把输出语句的打印位置改到某个文件中去。
try ( PrintStream ps = new PrintStream("XXX/XX/X"); ){
//把系统默认的打印流对象改成自己没置的打印流
System.setOut(ps);
//下边打印的内容都会打印到XXX/XX/X中去。
System.out.printLn("CSDN");
System.out.println("GLATY");
} catch (Exception e) {
e.printStackTrace();
}
数据流
DataOutputStream(数据输出流)
- 允许把数据和其类型一并写出去。
构造器 | 说明 |
public Data0utputStream(OutputStream out) | 创建新数据输出流包装基础的字节输出流 |
方法 | 说明 |
public final void writeByte(int v) throws IOException | 将byte类型的数据写入基础的字节输出流 |
public final void writeInt(int v) throws IOException | 将int类型的数据写入基础的字节输出流 |
public final void writeDouble(Double v) throws IOException | 将double类型的数据写入基础的字节输出流 |
public final void writeUTE(String str) throws IOException | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
public void write(int/byte[ ]/byte[ ]一部分) | 支持写字节数据出去 |
DatalnputStream(数据输入流)
- 用于读取数据输出流写出去的数据。
构造器 | 说明 |
public DataInputStream( InputStream is) | 创建新数据输入流包装基础的字节输入流 |
方法 | 说明 |
Public final byte readByte() throws IOException | 读取字节数据返回 |
public final int readInt() throws IOExcept ion | 读取int类型的数据返回 |
public final double readDouble() throws IOException | 读取double类型的数据返回 |
public final String readUTF() throws IOException | 读取字符串数(UTF-8) 据返回 |
public int readInt()/read(byte[]) | 支持读字节数据进来 |
序列化流
- 对象序列化:把Java对象写入到文件中去。
- 对象反序列化:把文件里的Java对象读出来。
- 成员变量前加上 transient 关键字这个成员变量将不参与序列化。
ObjectOutputStream(对象字节输出流)
- 可以把Java对象进行序列化:把Java对象存入到文件中去。
构造器 | 说明 |
public objectOutputStream(0utputStream out) | 创建对象字节输出流,包装基础的字节输出流 |
方法 | 说明 |
public final void write0bject(0bject o) throws IOException | 把对象写出去 |
- 对象如果需要序列化,必须实现序列化接口(Serializable)
- 一次序列化多个对象:用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可。(ArrayList集合已经实现了序列化接口)
objectInputStream(对象字节输入流)
●可以把Java对象进行反序列化:把存储在文件中的Java对象读入到内存中来。
构造器 | 说明 |
public ObjectInputStream( InputStream is) | 创建对象字节输入流,包装基础的字节输入流 |
方法 | 说明 |
public final Object readObject() | 把存储在文件中的Java对象读出来 |
IO框架
框架
●解决某类问题,编写的一套类、接口等,可以理解成一个半成品,大多框架都是第三方研发的。(需要下载并放到模块中去才可以使用)
●好处:在框架的基础上开发,可以得到优秀的软件架构,并能提高开发效率
●框架的形式:一般是把类、接口等编译成class形式,再压缩成一个jar结尾的文件发行出去。
IO框架
●封装了Java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。
Commons-io
- Commons-io是apache开源基金组织提供的一组有关I0操作的小框架,目的是提高I0流的开发效率。
导入commons-io-2.11.0.jar框架到项目中去
①在项目中创建一个文件夹: lib
②将commons-io-2.6.jar文件复 制到lib文件夹
③在jar文件上点右键,选择Add as Library ->点击0K
④在类中导包使用
FileUtils类提供的部分方法 | 说明 |
public static void copyFile(File srcFile, File destFile) | 复制文件 |
public static void copyDirectory(File srcDir, File destDir) | 复制文件夹 |
public static void deleteDirectory(File directory) | 删除文件夹 |
public static String readFileToString(File file, String encoding) | 读数据 |
public static void writeStringToFile(File file, String data, String charname, boolean append) | 写数据 |
l0Utils类提供的部分方法 | 说明 |
public static int copy( InputStream inputStream, OutputStream outputStream ) | 复制文件 |
public static int copy(Reader reader, Writer writer) | 复制文件 |
public static void write(String data, OutputStream output, String charsetName) | 写数据 |
注:Java提供的原生也可以一行代码搞定很多事情但功能上没有框架强大
java.nio. file.Files下的Files也可以实现一行代码复制文件/文件夹读数据等操作。