为什么需要io流呢?
如上图这些基本数据类型和对象以及列表都是内存中的数据,只要断电或者程序停止,这些数据将会永久消失。
那么如果我需要长久保存一些数据怎么办?(持久化)
那么就需要使用File对象 和 io流配合了。
File对象是Java中用于表示文件或目录的抽象。它提供了一些方法来查询和操作文件系统中的文件和目录。
通过File对象,你可以获取文件或目录的相关信息,如文件名、路径、大小、修改时间等。你还可以创建新的文件或目录,重命名或删除现有的文件或目录,以及进行文件系统的导航和搜索。
需要注意的是,File对象只是一个路径名的抽象表示,并不一定对应着实际的文件或目录。它可以指向存在的文件或目录,也可以指向还没有创建的文件或目录。
那么如何读写文件里面存储的数据呢?
那就是使用IO流进行读写了,io流可以读写文件中的数据或者是网络中的数据。
IO流指的是输入/输出流,是计算机程序中用于处理输入和输出的数据流。在程序中,输入流用于读取数据,输出流用于写入数据。IO流常用于文件操作、网络通信等场景。
IO流的分类:IO流主要有两种分类。
1、按照流的方向分类
2、按照流中数据的最小单位分类
所以大致的io流体系是:
Java的File
类有三个构造器,分别如下:
1.File(String pathname)
:使用给定的文件路径字符串创建一个File对象。
示例:
File file1 = new File("E:/path/to/file.txt");
2.File(String parent, String child)
:将父路径和子路径字符串组合起来创建一个File对象。
示例:
File file2 = new File("E:/path/to", "file.txt");
3.File(File parent, String child)
:将父File对象和子路径字符串组合起来创建一个File对象。
示例:
File parentDir = new File("E:/path/to");
File file3 = new File(parentDir, "file.txt");
其中构造file对象时路径中的/
路径分割符,file对象也提供了一个写法,就是 File.separator
所以也可以写为:
File file1 = new File("E:"+File.separator+"path"+File.separator+"to"+File.separator+"file.txt");
一般实际编码中,使用的都是相对路径,便于代码转移。相对路径是从当前工程下寻找文件。
File
类提供了很多常用的方法来操作文件和目录。以下是一些获取文件信息常用的方法和用法:1.exists()
:检查文件或目录是否存在,返回值为boolean 。
File file = new File("/path/to/file.txt");
boolean exists = file.exists();
2.isFile()
:检查File对象是否表示一个文件,返回值为boolean 。
File file = new File("/path/to/file.txt");
boolean isFile = file.isFile();
3.isDirectory()
:检查File对象是否表示一个目录,返回值为boolean。
File directory = new File("/path/to/directory");
boolean isDirectory = directory.isDirectory();
4.getName()
:获取文件或目录的名称,包含后缀。
File file = new File("/path/to/file.txt");
String name = file.getName();
5.length()
:获取文件的长度(大小)(以字节为单位)。
File file = new File("/path/to/file.txt");
long length = file.length();
6.getParentFile()
:获取文件或目录的父File对象。
File file = new File("/path/to/file.txt");
File parentDir = file.getParentFile();
7.getParent()
:获取文件或目录的父路径。
File file = new File("/path/to/file.txt");
String parent = file.getParent();
8.listFiles()
:获取目录中的所有文件和子目录作为File对象的数组。
File directory = new File("/path/to/directory");
File[] files = directory.listFiles();
9.getPath()
:获取到创建文件对象时使用的路径
File file = new File("E:\\io\\src\\a.txt");
String path = file.getPath();
10..getAbsolutePath()
获取到当前文件的绝对路径。
File file = new File("E:\\io\\src\\a.txt");
String absolutePath = file.getAbsolutePath();
File
类提供了一些方法来创建和删除文件。下面是创建和删除文件的方法:创建文件:
createNewFile()
:创建一个新的空文件。如果文件已存在,则返回 false
。
File file = new File("/path/to/newFile.txt");
boolean created = file.createNewFile();
mkdir()
:创建一个新的空目录(只能创建一级)。如果目录已存在或创建失败,则返回 false
。
File dir = new File("/path/to/newDir");
boolean created = dir.mkdir();
mkdirs()
:创建一个新的目录,包括所有不存在的父目录(可以创建多级)。如果目录已存在或创建失败,则返回 false
。
File dir = new File("/path/to/newDir/subDir");
boolean created = dir.mkdirs();
删除文件或空目录:
delete()
:删除文件或空目录。如果删除成功,则返回 true
;否则,返回 false
。
File file = new File("/path/to/file.txt");
boolean deleted = file.delete();
File dir = new File("/path/to/directory");
boolean deleted = dir.delete();
请注意,上述方法只能删除空目录或文件。如果要删除非空目录,需要使用递归删除。
public static void deleteDirectory(File directory) {
if (!directory.exists()) {
return;
}
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteDirectory(file); // 递归删除子目录
} else {
file.delete(); // 删除文件
}
}
}
directory.delete(); // 删除当前目录
}
调用 deleteDirectory()
方法以删除非空目录:
File dir = new File("/path/to/directory");
deleteDirectory(dir);
记住,在进行文件和目录操作时,要小心处理异常情况,并确保在操作之前检查文件和目录的存在性。
File
类提供了一些方法来遍历文件。下面是遍历文件的方法:主要的字符集编码有 ASCII
,UTF-8
,GBK
等
使用read()
读取,每次返回一个字符,代码示范:
缺点:
package day0927;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class demo3 {
public static void main(String[] args) {
InputStream in = null;
try {
in = new FileInputStream("src\\a.txt");
int b;
while ((b = in.read()) != -1){
System.out.print((char) b);
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
//读取完之后关闭流
if (in!= null)
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
使用read(byte[] buffer)
读取,每次读取字节数组的长度,代码示范:
优点:
缺点:
package day0927;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class demo3 {
public static void main(String[] args) {
InputStream in = null;
try {
in = new FileInputStream("src\\a.txt");
//设置每次读取多少字节,一般是写 1024*n
byte[] buffer = new byte[3];
int b;
while ((b = in.read( buffer )) != -1){
//注意:读取多少就倒多少
String str = new String(buffer,0,b);
System.out.print(str);
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
if (in!= null)
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
以上两种方式都是读取中文会乱码,可以使用直接读取整个文件字符,则不会乱码。
第一种方法(获取文件大小,定义一个和文件一样大小的字节数组一次性读取):
package day0927;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class demo3 {
public static void main(String[] args) {
InputStream in = null;
try {
//获取文件的file对象
File file = new File("src\\a.txt");
//获取文件的字节长度
long length = file.length();
in = new FileInputStream(file);
//字节数组的长度改为文件长度
byte[] buffer = new byte[(int) length];
//一次性读取
in.read(buffer);
System.out.println(new String(buffer));
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
if (in!= null)
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
第二种方法 JDK11新增的特性readAllBytes()
:
一顶是JDK11以上才可以使用否则报错。
FileInputStream in = new FileInputStream("src\\a.txt");
byte[] buffer = in.readAllBytes();
System.out.println(new String(buffer));
使用write()
输出字符。
package day0927;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo4 {
public static void main(String[] args) {
FileOutputStream out = null;
try {
//参数1文件的位置,参数2是否是追加,默认false
out = new FileOutputStream("src\\b.txt",true);
out.write("你好,JAVA".getBytes());
//out.write('97'); 写入字符a
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
当学会了文件输出输入流之后,就可以完成文件的拷贝案例了。
使用文件输出输入流是所有的文件都可以进行复制的,下面是代码示范:
package day0927;
import java.io.*;
public class demo5 {
public static void main(String[] args) {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream("D:\\asdf.jpg");
out = new FileOutputStream("E:\\asdf.jpg");
byte[] buffer = new byte[1024];
int b;
while ((b = in.read(buffer))!= -1){
out.write(buffer,0,b);
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
try {
if (out != null)
out.close();
if (in != null)
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
如上代码看起来写得特别的臃肿,因为各种释放资源,所以这里就要使用到 JDK7提出得新特性:
如图在try中写资源,当执行完之后会自动调用其close()
方法。示范代码:
package day0927;
import java.io.*;
public class demo5 {
public static void main(String[] args) {
try (
InputStream in = new FileInputStream("D:\\asdf.jpg");
OutputStream out = new FileOutputStream("E:\\asdf.jpg");
){
byte[] buffer = new byte[1024];
int b;
while ((b = in.read(buffer))!= -1){
out.write(buffer,0,b);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
以下代码示范就是字符流读取文件,分别有一次读取一个字符和读取多个字符。
package day0927;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class demo6 {
public static void main(String[] args) {
try (
FileReader reader = new FileReader("src\\a.txt");
){
//一次读一个字符,性能消耗较高
// int d;
// while ((d = reader.read())!=-1){
// System.out.print((char)d);
// }
//一次读多个字符,性能消耗低
char[] buffer = new char[3];
int d;
while ((d = reader.read(buffer))!=-1){
//读多少就倒多少
System.out.print(new String(buffer,0,d));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
下面是FileWriter文件字符输出流的代码演示:
package day0927;
import java.io.FileWriter;
import java.io.IOException;
public class demo7 {
public static void main(String[] args) {
try (
//覆盖的写法
// FileWriter writer = new FileWriter("src\\c.txt");
//追加的写法
FileWriter fileWriter = new FileWriter("src\\c.txt",true);
){
//写一个字符
fileWriter.write(97);
fileWriter.write("流");
fileWriter.write('a');
//写一个字符串
fileWriter.write("我爱你中国asdf");
//写一个字符串得一部分
fileWriter.write("我爱你中国asdf",0,5);
//写一个字符数组
char[] chars = {98,'s','牛','马'};
fileWriter.write(chars);
//写一个字符数组得一部分出去
fileWriter.write(chars,1,2);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package day0927;
import java.io.FileReader;
import java.io.FileWriter;
public class demo8 {
public static void main(String[] args) {
try (
FileReader fileReader = new FileReader("src\\a.txt");
FileWriter fileWriter = new FileWriter("src\\d.txt");
){
char[] buffer = new char[3];
int b;
while ((b = fileReader.read(buffer)) != -1){
fileWriter.write(buffer,0,b);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
因为使用字符流输出数据是先建立了一个缓冲区,把所有要写的字符先存到了这,而不是直接存到目标文件,所以需要flush()
刷新或者close()
关闭流进行保存,如果不使用flush()
刷新或者不使用close()
关闭流那么就不会保存,但是当缓冲区数据堆满时,它会自动进行一次flush()
刷新也就是自动保存一次。