一、File文件操作类
概念: java.io.File
类是文件和目录路径的抽象表示,主要用于文件本身操作(创建、删除、取得信息…),与平台无关。
1.构造方法
方法 | 功能 |
---|---|
public File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 |
public File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的 File实例 |
public File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的 File实例 |
// 文件路径名(文件)
String pathname = "D:\\aaa.txt"; //相对路径:相对于当前module
File file1 = new File(pathname);
// 文件路径名(目录)
String pathname2 = "D:\\aaa\\bbb.txt"; //绝对路径:包含盘符在内的文件或文件目录的路径
File file2 = new File(pathname2);
// 通过父路径和子路径字符串
String parent = "d:\\aaa";
String child = "bbb.txt";
File file3 = new File(parent, child);
// 通过父级File对象和子路径字符串
File parentDir = new File("d:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child);
补充:
- 一个File对象代表硬盘中实际存在的一个文件或者目录。
- 无论该路径下是否存在文件或者目录,都不影响File对象的创建。
2.常用普通方法
方法 | 功能 |
---|---|
public boolean createNewFile() throws IOException | 创建一个新文件 |
public boolean exists() | 判断文件是否存在 |
public boolean delete() | 删除文件 |
public class Test {
public static void main(String[] args) {
File file = new File("D:"+File.separator+"test"+File.separator+"hello world.txt");
if (file.exists()){
//文件存在,进行删除
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.目录操作之目录的创建与删除
方法名 | 功能 |
---|---|
public String getParent() | 获取父路径 |
public File getParentFile() | 获取父File对象 |
public boolean mkdirs() | 创建多级目录 |
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
File file = new File("D:"+File.separator+"test"+File.separator+"hello world.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();//如果父路径不存在就创建多级目录
}
if (file.exists()){
file.delete();//如果文件存在就进行删除
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.目录操作之目录的遍历
方法名 | 功能 |
---|---|
public String[] list() | 返回一个String数组,表示该File目录中的所有子文件或目录 |
public File[] listFiles() | 返回一个File数组,表示该File目录中的所有的子文件或目录 |
public class FileFor {
public static void main(String[] args) {
File dir = new File("d:\\java_code");
//获取当前目录下的文件以及文件夹的名称。
String[] names = dir.list();
for(String name : names){
System.out.println(name);
}
//获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file);
}
}
}
注:调用listFiles()
方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。
5.取得文件信息
方法名 | 功能 |
---|---|
public boolean isFile() | 判断路径是否是文件 |
public boolean isDiretory() | 判断路径是否是目录 |
public long length() | 取得文件大小(字节) |
public long lastModified() | 最后一次修改日期 |
import java.io.File;
public class Test {
public static void main(String[] args) {
File file = new File("C:"+File.separator+"Desktop");
listAllFiles(file);
}
private static void listAllFiles(File file) {
if (file.isDirectory()){//是目录
File[] result = file.listFiles();//列出该级目录内容
if (result != null){
for (File file1 : result){
listAllFiles(file1);
}
}
}else {
//是文件直接打印
System.out.println(file);
}
}
}
二、I/O流概述
1.什么是IO?
数据在内存和硬盘间的读取和写入。
2.流的分类
- 按流的数据单位不同分为:字节流(8bit),字符流(16bit)
- 按数据的流向(以内存为参考点)不同分为:输入流和输出流
- 按流的角色的不同分为:节点流,处理流
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
- Java的IO流共涉及40多个类,实际上非常规则,都是从这四个抽象基类派生的
- 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀
三、字节流
1.一切皆字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
2. 字节输出流【OutputStream】
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
方法名 | 功能 |
---|---|
public void close() | 关闭此输出流并释放与此流相关联的任何系统资源 |
public void flush() | 刷新此输出流并强制任何缓冲的输出字节被写出 |
public void write(byte[] b) | 将 b.length字节从指定的字节数组写入此输出流 |
public void write(byte[] b, int off, int len) | 从指定的字节数组写入 len字节,从偏移量 off开始输 出到此输出流 |
注: close方法,当完成流的操作时,必须调用此方法,释放系统资源。
3.FileOutputStream–文件字节输出流
功能: 把内存中的数据写入到硬盘的文件中
3.1构造方法
方法名 | 功能 |
---|---|
public FileOutputStream(File file) | 创建文件输出流以写入由指定的 File对象表示的文件 |
public FileOutputStream(String name) | 创建文件输出流以指定的名称写入文件 |
参数: 写入数据的目的地
- String name:目的地是一个文件的路径
- File file:目的地是一个文件
构造方法的作用:
- 创建一个FileOutputStream对象
- 会根据构造方法中传递的文件/文件路径,创建一个空的文件
- 会把FileOutputStream对象指向创建好的文件
注意:
当创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,则会自动创建该文件。如果有这个文 件,会清空这个文件的数据。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws FileNotFoundException {
//使用File对象创建流对象
File file = new File("a.txt");
FileOutputStream fos1 = new FileOutputStream(file);
//使用文件名创建流对象
FileOutputStream fos2 = new FileOutputStream("b.txt");
}
}
3.2写入字节
写入数据的原理:(内存–>硬盘)
java程序–>JVM(Java虚拟机)–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
字节输出流的使用步骤【重点】:
- 创建一个FileOutputStream对象,构造方法中传入写入数据的目的地。
- 调用FileOutputStream对象的方法write,把数据写入到文件中。
- 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)。
3.2.1写入字节数据
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
//写出数据
fos.write(97);
//关闭资源
fos.close();
}
}
//输出结果:a
注意: 虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
3.2.2写入字节数组
write(byte[] b)
:每次可以写出数组中的数据。
- 如果写的第一个字节是正数(0~127),那么显示的时候会查询ASCII码表
- 如果写的第一个字节是负数,那第一个字节会和第二个字节组成一个中文显示,查询系统默认码表(GBK)
面试题: 在文件中写入100,要写入几个字节?3个
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象,构造方法中绑定要写入数据的目的地
FileOutputStream fos = new FileOutputStream(new File("fos.txt"));
byte[] b = {49,48,48};
//写出字节数组数据
fos.write(b);
//关闭资源
fos.close();
}
}
//输出结果:100
3.2.3 写入指定长度字节数组
write(byte[] b, int off, int len)
:把字节数组的一部分写入到文件。
- int off:数组的开始索引
- int len:写几个字节
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
//字符串转为字节数组
byte[] b = "abcdefg".getBytes();
//写出从索引2开始,两个字节
fos.write(b,2,2);
//关闭资源
fos.close();
}
}
//输出结果:cd
3.2.4写入字符串
可以使用String类中的方法byte[] getBytes()
把字符串转换为字节数组。
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("a.txt");
//字符串转换为字节数组
byte[] bytes = "你好".getBytes();
System.out.println(Arrays.toString(bytes));//[-28, -67, -96, -27, -91, -67]
//写入字节数组数据
fos.write(bytes);
//释放资源
fos.close();
}
}
注: 由于IDEA所用的编码格式是UTF-8,所以两个汉字是6个字节。
3.3数据追加续写
方法名 | 功能 |
---|---|
public FileOutputStream(File file, boolean append) | 创建文件输出流以写入由指定的 File对象表示的 文件 |
public FileOutputStream(String name, boolean append) | 创建文件输出流以指定的名称写入文件 |
参数:
- File file,String name:写入数据的目的地
- boolean append:追加写开关(true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据;false:创建一个新文件,覆盖源文件)
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt",true);
//字符串转为字节数组
byte[] b = "abcdefg".getBytes();
//写出从索引2开始,两个字节
fos.write(b,2,2);
//关闭资源
fos.close();
}
}
//文件操作前:cd
//文件操作后:cdabcdefg
3.4写出换行
Windows系统里,换行符号是 \r\n
。把
以指定是否追加续写了。
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt",true);
//定义字节数据
byte[] words = {97,98,99,100,101};
//遍历数组
for (byte b:words){
//写出一个字节
fos.write(words[b]);
//写出一个换行,换行符号装成数组写出
fos.write("\r\n".getBytes());
}
//关闭资源
fos.close();
}
}
/*
输出结果:
a
b
c
d
e
*/
4.字节输入流【InputStream】
java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入
流的基本共性功能方法。
方法名 | 功能 |
---|---|
public void close() | 关闭此输入流并释放与此流相关联的任何系统资源 |
public abstract int read() | 从输入流读取数据的下一个字节 |
public int read(byte[] b) | 从输入流中读取一些字节数,并将它们存储到字节数组 b中 |
5.FileInputStream–文件字节输入流
功能: 把硬盘文件中的数据读取到内存中使用。
5.1构造方法
方法名 | 功能 |
---|---|
FileInputStream(File file) | 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系 统中的 File对象 file命名 |
FileInputStream(String name) | 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件 系统中的路径名 name命名 |
参数: 读取文件的数据源(文件/文件的路径)
构造方法的作用:
- 会创建一个FileInputStream对象。
- 会把FileInputStream对象指向构造方法中要读取的文件。
注意:
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出 FileNotFoundException 。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Test {
public static void main(String[] args) throws FileNotFoundException {
//使用File对象创建流对象
File file = new File("a.txt");
FileInputStream fis1 = new FileInputStream(file);
//使用文件名称创建流对象
FileInputStream fis2 = new FileInputStream("b.txt");
}
}
5.2读取字节
读取数据的原理:(硬盘–>内存)
Java程序–>JVM–>OS->OS读取数据的方法–>读取文件
字节输出流的使用步骤:
- 创建FileInputStream对象,构造方法中绑定要读取的数据源
- 使用FileInputStream对象中的read方法,读取文件
- 释放资源
5.2.1读取字节数据
read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回 -1 。
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名创建流对象
FileInputStream fis = new FileInputStream("a.txt");
int len = 0;
while ((len = fis.read()) != -1) {
System.out.print((char) len);//abc
}
//释放资源
fis.close();
}
}
5.2.2使用字节数组读取
read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
明确两件事:
- 方法参数
byte[]
的作用:①起到缓冲作用,存储每次读取到的多个字节;②数组的长度一般定义为1024(1kb)或者1024的整数倍。 - 方法返回值int是什么?每次读取的有效字节个数
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//使用文件名称创建流对象
FileInputStream fis = new FileInputStream("b.txt");
byte[] bytes = new byte[1024];//存储读取到的多个字节
int len = 0;//记录每次读取的有效字节个数
while ((len = fis.read(bytes)) != -1) {
//String(byte[] bytes,int offset,int length):把字节数组一部分转换为字符串,offset:数组的开始索引;length:转换的个数
System.out.println(new String(bytes, 0, len));//ABCDE
}
//释放资源
fis.close();
}
}
5.3图片复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//1.创建一个字节输入流对象,构造方法中要绑定的数据源
FileInputStream fis = new FileInputStream("c:\\1.jpg");
//2.创建一个字节输出流对象,构造方法中要绑定的数据源
FileOutputStream fos = new FileOutputStream("d:\\1.jpg");
//3.使用数组缓冲读取多个字节,写入多个字节
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes))!= -1){
//4.使用字节输出流的方法把读取到的字节写入到目的地文件中
fos.write(bytes,0,len);
}
//5.释放资源
fos.close();
fis.close();
}
}
四、字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
1.字符输入流【Reader】
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
方法名 | 功能 |
---|---|
public int read() | 从输入流读取一个字符 |
public int read(char[] cbuf) | 从输入流中读取一些字符,并将它们存储到字符数组cbuf中 |
public void close() | 关闭此流并释放与此流相关联的任何系统资源 |
1.1FileReader类
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
- 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。idea中UTF-8。
- 字节缓冲区:一个字节数组,用来临时存储字节数据。
构造方法:
方法名 | 功能 |
---|---|
FileReader(File file) | 创建一个新的FileReader ,给定要读取的File对象 |
FileReader(String fileName) | 创建一个新的FileReader ,给定要读取的文件的名称。 |
构造举例:
public class FileReaderConstructor throws IOException{
public static void main(String[] args) {
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
}
}
1.2读取字符
read():返回读入的一个字符,如果达到文件末尾,返回-1
package Filele类;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
* @BelongsProject: untitled
* @BelongsPackage: Filele类
* @Author: mcc
* @CreateTime: 2020-11-23 07:51
* @Description:
*/
public class FileResderWriterTest {
/**
* 将该Module下的hello.txt内容读入程序中,并输出到控制台
*/
@Test
public void testFileReader(){
FileReader fr = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
说明点:
- 为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally来处理
- 读入的文件一定要存在,否则就会报FileNotFoundException
1.3使用字符数组读取
read(char[] cbuf)
,每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1 。
//对read()操作升级,使用read的重载方法
@Test
public void testFileReader1() {
FileReader fr = null;
try {
//1.File类的实例化
File file = new File("hello.txt");
//2.FileReader流的实例化
fr = new FileReader(file);
//3.读入操作
char[] arr = new char[5];
int len;
while ((len = fr.read(arr)) != -1) {
for (int i = 0; i < len; i++) {
System.out.print(arr[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null){
//4.资源关闭
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.字符输入流
/**
* 从内存中写出数据到硬盘的文件里
*/
@Test
public void testFileWriter() throws IOException {
FileWriter fw = null;
try {
//1.提供File类的对象,指明写出到的文件
File file = new File("hello1.txt");
//2.提供FileWriter的对象,用于数据的写出
fw = new FileWriter(file);
//3.写出操作
fw.write("I have a dream!");
fw.write("You need to have a dream!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
说明:
- 输出操作对应的file可以不存在,并不会报异常
- file对应的硬盘中的文件,如果不存在,在输出的过程中会自动创建此文件
- file对应的硬盘中的文件,如果存在:如果流使用的构造器是
FileWriter(file,false)
或FileWriter(file)
,则会对原有文件进行覆盖;如果流使用的构造器是FileWriter(file,true)
,不会对原文件覆盖,而是在原有文件基础上追加内容
3.文本文件复制
import org.junit.Test;
import java.io.*;
/**
* @BelongsProject: untitled
* @BelongsPackage: Filele类
* @Author: mcc
* @CreateTime: 2020-11-23 07:51
* @Description:
*/
public class FileResderWriterTest {
@Test
public void testFileResderWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hello3.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while ((len = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, len);//每次写出len个字符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
try {
if (fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}