java文件和流的相关知识点总结
- 文件类File
- 构造方法
- 常用方法
- 斐波那契数列
- 递归遍历文件夹
- IO
- 流Stream
- 流的分类
- 字节输入流InputStream
- 字节输出流OutputStream
- 字符输入流Reader
- 字符输出流Writer
- 流的四个父类的特点
- FileInputStream文件字节输入流(掌握)
- 构造方法
- 常用方法
- FileOutputStream文件字节输出流(掌握)
- 构造方法
- 常用方法
- 使用FileInputStream和FileOutputStream读写时的注意事项
- 使用FileInputStream和FileOutputStream实现单文件的复制
- 文件夹的复制
- FileReader文件字符输入流
- 构造方法
- 常用方法
- FileWriter文件字符输出流
- 构造方法
- 常用方法
- BufferedReader缓冲字符输入流(掌握)
- 构造方法
- 常用方法
- 读取文本练习
- BufferedWriter缓冲字符输出流(掌握)
- 构造方法
- 常用方法
- 写入文本练习
- ObjectOutputStream对象字节输出流(序列化)(掌握)
- 构造方法
- 常用方法
- ObjectInputStream对象字节输入流(反序列化)(掌握)
- 构造方法
- 常用方法
- 序列化和反序列化案例
- 转换流
- OutputStreamWriter
- InputStreamReader
- 转换流的使用
文件类File
Java中的File类,表示本地硬盘中的文件(文件和目录)的一个类。
通过这个类创建的对象,可以操作对应的文件。
构造方法
常用构造方法 | 说明 |
File(String pathName) | 根据文件的完整路径创建File对象 |
File(String parent,String child) | 根据文件的父目录路径和自身路径创建File对象 |
File(File parent,String child) | 根据文件的父目录对应的File对象和自身路径创建File对象 |
//如想要表示 “F:\221001\笔记\面向对象部分回顾.pdf” 这个文件
//File(String pathName)
File file1 = new File("F:\\221001\\笔记\\面向对象部分回顾.pdf");
//File(String parent,String child)
File file2 = new File("F:\\221001\\笔记", "面向对象部分回顾.pdf");
//File(File parent,String child)
File parent = new File("F:\\221001\\笔记");
File file3 = new File(parent, "面向对象部分回顾.pdf");
//file1、file2、file3都表示同一个文件
常用方法
常用方法 | 说明 |
exists() | 判断文件是否存在 |
isFile() | 判断是否为文件 |
isDirectory() | 判断是否为目录 |
getName() | 获取文件名 |
getPath() | 获取文件相对路径 |
getAbsolutePath() | 获取文件绝对路径 |
getParent() | 获取父目录的名称 |
getParentFile() | 获取父目录对象 |
lastModified() | 获取最后一次修改时间对应的毫秒数 |
length() | 获取文件所占字节 |
isHidden() | 判断文件是否隐藏 |
delete() | 删除文件或空目录 |
renameTo(File newFile) | 将原文件重命名且移动到指定目录 |
mkdir() | 创建目录 |
list() | 获取某个目录下的第一层子文件的名称的数组 |
listFiles() | 获取某个目录下的第一层子文件对象的数组 |
斐波那契数列
package com.hqyj.FileTest;
public class Test2 {
public static void main(String[] args) {
//兔子问题
//有一对兔子在第三个月开始,每个月都能生一对小兔子
//如果所有兔子不死亡,且每次生下的都是一雌一雄,问10个月后共有多少对兔子
//1月 2月 3月 4月 5月 6月 7月 8月 9月 10月
//1 1 2 3 5 8 13 21 34 55
//斐波那契数列
//f(n)=f(n-1)+f(n-2) n>2
Test2 t = new Test2();
System.out.println(t.f(20));
}
/*
* 递归方法
* */
public int f(int n) {
if (n > 2) {
return f(n - 1) + f(n - 2);
}
return 1;
}
}
递归遍历文件夹
package com.hqyj.FileTest;
import java.io.File;
import java.util.Date;
public class Test3 {
//查看某个目录下的所有文件
public static void main(String[] args) {
File source = new File("E:\\adobe");
Test3 t = new Test3();
t.fun(source);
}
/*
* 递归遍历文件夹
* */
public void fun(File source) {
//输出某个目录中超过3个月未使用且大于500MB的文件
/*
long start = source.lastModified();
long end = System.currentTimeMillis();
if ((end - start) / 1000 / 3600 / 24 > 90 && source.length() / 1024 / 1024 > 500) {
System.out.println(source.getName() + "\t" + new Date(source.lastModified()) + "\t" + source.length() / 1024 / 1024);
}*/
//判断是否为目录
if (source.isDirectory()) {
//将其展开
for (File child : source.listFiles()) {
//因为子文件有可能是目录,继续调用本方法
fun(child);
}
}
}
}
IO
I:Input输入
O:Output输出
流Stream
在Java中,流用于表示计算机硬盘与内存之间传输数据的通道。
将内存中的数据存入到硬盘中,称为写write,也称为输出Output。
将硬盘中的数据存入到内存中,称为读read,也称为输入Input。
流的分类
Java中将流定义为类,以对象的形式表现流。流有"四大家族",是所有流的父类。
字节输入流InputStream
FileInpuStream、ObjectInputStream
字节输出流OutputStream
FileOutputStream、ObjectOutputStream
字符输入流Reader
FileReader、BufferedReader、OutputStreamWriter
字符输出流Writer
FileWriter、BufferedWriter、InputStreamReader
按方向分类
- 输入流:InputStream、Reader
- 将硬盘中的数据读取到内存中
- 输出流:OutputStream、Writer
- 将内存中的数据写入到硬盘中
按类型分
- 字节流:InputStream、OutputStream
- 读写非文本类型文件。如图片、音视频、其他文件等。
- 字符流:Reader、Writer
- 读写纯文本类型文件。如txt、md等
如要将硬盘中某个txt文件中的内容读取到程序中,使用Reader
如要将硬盘中的某个图片读取到程序中,使用InputStream
如要将程序中的文本写入到硬盘中为txt类型文件时,使用Writer
如要将程序中的数据写入到硬盘中为非文本文件时,使用OutputStream
流的四个父类的特点
- 这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
- 这四个父类中都定义了close()方法,用于关闭流对象,释放资源
- 输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数据到硬盘中
- 输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中
- 在使用输出流对象时,一定要调用flush()或close()方法后,才能真正将数据写入到硬盘中
- 所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字符流,数据以字符传输
- 读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件可以不存在,但父目录必须存在。
- 读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流
FileInputStream文件字节输入流(掌握)
按字节读取硬盘中的文件。
构造方法
常用构造方法 | 说明 |
FileInputStream(String pathName) | 根据文件名创建流对象 |
FileInputStream(File file) | 根据文件对象创建流对象 |
常用方法
常用方法 | 说明 |
read() | 读取一个字节,返回读取到的字节 |
read(byte[] bytes) | 按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组中 |
close() | 关闭流对象 |
FileOutputStream文件字节输出流(掌握)
按字节将内存中的数据写入到硬盘中。
构造方法
常用构造方法 | 说明 |
FileOutputStream(String pathname) | 根据文件名创建输出流对象,写入时覆盖原内容 |
FileOutputStream(String pathname,boolean append) | 根据文件名创建输出流对象,第二个参数为true,写入时追加在原内容之后 |
FileOutputStream(File file) | 根据文件对象创建输出流对象,写入时覆盖原内容 |
FileOutputStream(File file,boolean append) | 根据文件对象创建输出流对象,第二个参数为true,写入时追加在原内容之后 |
常用方法
常用方法 | 作用 |
write(int i) | 写入一个指定字节 |
write(byte[] bytes) | 写入一个字节数组 |
write(byte[] bytes,int off,int len) | 写入字节数组中从off开始的len个字节 |
flush() | 将流中的数据冲刷到硬盘中 |
close() | 关闭流对象 |
使用FileInputStream和FileOutputStream读写时的注意事项
- 在通过FileInputStream对象使用read(byte[] bytes)方法时,每次读取指定数组的字节,将读取到的字节保存在字节数组中,该方法返回读取到的字节数量。如果最后一次读取的字节数不足字节数组的大小时,只会将读取到内容覆盖数组中最前的几个元素。所以会导致读取到的内容多于实际内容。
- 在通过FileOutputStream对象使用write(byte[] bytes)方法时,会将字节数组中的所有内容写入到输出流中,在最后一次写入时,可能会写入多余的内容。所以在写入时,最好使用write(byte[] bytes,int off,int lef)方法,表示将字节数组中的内容,从off开始写入len个。
如有word.txt文件,其中保存aaabbbccc
FileInputStream fis = new FileInputStream("d:/word.txt");
FileOutputStream fos = new FileOutputStream("d:/copy.txt");
byte[] bytes = new byte[4];
//第一次读取4个字节,即aaab,count为4
int count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第二次读取4个字节,即bbcc,count为4
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第三次读取1个字节c,覆盖数组中的第一个元素,即数组现在为cbcc,count为1
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);//最终会写入aaabbbcccbcc
fos.write(bytes,0,count);//这样最后一次只会写入实际读取到的c
fos.close();
fis.close();
使用FileInputStream和FileOutputStream实现单文件的复制
package com.hqyj.IOTest;
import java.io.*;
public class CopyFile {
public static void main(String[] args) throws IOException {
//定义原文件和目标文件
File source = new File("F:\\221001\\录屏\\FileInputStream和FileOutputStream.mp4");
File target = new File("F:\\221001\\copy.mp4");
//定义文件字节输入流,用于读取原文件
FileInputStream fis = new FileInputStream(source);
//定义文件字节输出流,用于写入文件
FileOutputStream fos = new FileOutputStream(target);
/*
//调用无参的read()方法,表示读取一个字节,返回读取到的字节
int read = fis.read();
//如果能读取到内容
while (read > -1) {
//将读取到的内容写入到文件中
fos.write(read);
//继续读取
read = fis.read();
}
*/
//定义一个字节数组,大小为8MB
byte[] bytes = new byte[1024 * 1024 * 8];
//按字节数组读取,返回读取到的字节数量
int count = fis.read(bytes);
//循环读取写入
while (count > -1) {
//将读取的字节数组写入到文件中
// fos.write(bytes);//如果调用该方法,最后一次会多写入上一次残留的数据
fos.write(bytes,0,count);//如果调用该方法,实际读取到了多少字节就写入多少
count = fis.read(bytes);
}
fis.close();
fos.close();
if (target.exists()) {
System.out.println("复制成功");
}
}
}
文件夹的复制
package com.hqyj.IOTest;
import java.io.*;
public class CopyDirectory {
public static void main(String[] args) {
/*File source = new File("F:\\221001\\录屏\\流的基本概念.mp4");
File target = new File("F:\\221001\\copy.mp4");
copyFile(source, target);*/
File source = new File("F:\\221001\\笔记");
File target = new File("F:\\221001\\笔记副本");
/*
* source F:\221001\笔记
* target F:\221001\笔记副本
* 1.调用copyDir方法,判断发现source是一个文件夹,创建目标文件夹target:“F:\221001\笔记副本”
* 2.遍历source,如其中有xxx.md文件,即child
* 此时的source是F:\221001\笔记\xxx.md,即child
* 此时的target是F:\221001\笔记副本\xxx.md,用File(File parent,String child)构造方法表示这个目标文件
* 所以创建File newTarget = new File(target,child.getName())
*
* */
copyDir(source, target);
}
/*
* 定义复制文件夹的方法
* */
public static void copyDir(File source, File target) {
//如果是文件,调用单文件复制的方法
if (source.isFile()) {
copyFile(source, target);
} else {//如果是文件夹
//创建要复制的目标文件夹
target.mkdir();
//展开原文件夹
for (File child : source.listFiles()) {
//定义复制后的新目标文件
//如source为F:\221001\笔记\day1.md时,递归调用的target为F:\221001\笔记副本\day1.md
File newTarget = new File(target, child.getName());//这里使用File(File parent,String child)构造方法创建target对象
//递归调用的原文件依然是当前遍历出来的子文件,目标文件就是最终复制的F:\221001\笔记副本\day1.md
copyDir(child, newTarget);
}
}
}
/*
* 定义单文件复制的方法
* */
public static void copyFile(File source, File target) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建用于输入输出的流对象
fis = new FileInputStream(source);
fos = new FileOutputStream(target);
//定义字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
//按数组读取
int count = fis.read(bytes);
while (count != -1) {
fos.write(bytes, 0, count);
count = fis.read(bytes);
}
} catch (FileNotFoundException e) {
System.out.println("文件不存在" + e);
} catch (IOException e) {
System.out.println("读写异常" + e);
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
System.out.println("关闭流对象异常" + e);
}
}
}
}
断点调试执行细节
FileReader文件字符输入流
按字符读取文件。
构造方法
常用构造方法 | 说明 |
FileReader(String fileName) | 根据文件名创建文件字符输入流对象 |
FileReader(File file) | 根据文件对象创建文件字符输入流对象 |
常用方法
常用方法 | 作用 |
ready() | 判断是否还有下一个字符 |
read() | 读取下一个字符,返回读取到的字符 |
read(char[] chars) | 按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组中 |
close() | 关闭流对象 |
FileWriter文件字符输出流
按字符写入文件。
构造方法
常用构造方法 | 作用 |
FileWriter(String fileName) | 按文件名创建字符输出流对象,覆盖写入 |
FileWriter(String fileName,boolean append) | 按文件名创建字符输出流对象,如果append为true,表示追加写入 |
FileWriter(File file) | 按文件对象创建字符输出流对象,覆盖写入 |
FileWriter(File file,boolean append) | 按文件对象创建字符输出流对象,如果append为true,表示追加写入 |
常用方法
常用方法 | 作用 |
write(String str) | 按字符串写入 |
flush() | 将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真正写入 |
close() | 关闭流对象 |
BufferedReader缓冲字符输入流(掌握)
自带缓冲区(字符数组)的字符输入流。默认字符数组大小为8192,每次最多读取8192个字符。
在读取纯文本文件(txt或md)时,首选该类。
构造方法
常用构造方法 | 作用 |
BufferedReader(Reader in) | 创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象,参数为Reader类型对象,Reader是抽象类,所以实际参数为Reader的子类,如FileReader,在FileReader对象中定义要读取的文件 |
BufferedReader(Reader in,int size) | 创建一个指定缓冲区(字符数组)大小的字符输入流对象 |
常用方法
常用方法 | 作用 |
ready() | 判断是否还有字符 |
readLine() | 读取整行字符 |
close() | 关闭流对象 |
读取文本练习
package com.hqyj.ReaderAndWriter;
import java.io.*;
public class Test2 {
public static void main(String[] args) throws IOException {
/*
File file = new File("F:\\221001\\笔记\\Java基础回顾.md");
//FileReader(File file)
Reader fr = new FileReader(file);
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(fr);
*/
//创建带有缓冲区的字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("F:\\221001\\笔记\\Java基础回顾.md"));
//循环判断是否还有字符
while (br.ready()) {
//读取整行
System.out.println(br.readLine());
}
//关闭最大的流对象即可
br.close();
}
}
BufferedWriter缓冲字符输出流(掌握)
自带缓冲区(字符数组)的字符输出流
构造方法
常用构造方法 | 说明 |
BufferedWriter(Writer writer) | 创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象,Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在FileWriter中定义要将输入写入的目标文件 |
BufferedWriter(Writer writer,int size) | 创建一个指定缓冲区大小的字符输出流对象 |
常用方法
常用方法 | 作用 |
write(String str) | 写入字符串 |
newLine() | 换行 |
flush() | 冲刷流中的数据到硬盘 |
close() | 关闭流对象 |
写入文本练习
package com.hqyj.ReaderAndWriter;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.SimpleFormatter;
public class Test3 {
public static void main(String[] args) throws IOException {
File file = new File("221001.txt");
//创建缓冲字符输入流对象,读取文本
BufferedReader br = new BufferedReader(new FileReader(file));
//创建集合,保存读取到的姓名
ArrayList<String> list = new ArrayList<>();
//循环读取文件中的所有字符
while (br.ready()) {
String name = br.readLine();
list.add(name);
}
//关闭
br.close();
//打乱集合中的元素
Collections.shuffle(list);
//创建日期字符串
String today = new SimpleDateFormat("yyyy.MM.dd").format(new Date());
//创建缓冲字符输出流,用于写文本,文件名为"日期+作业情况.txt",如果每次都是新建,这样写
// BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情况.txt"));
//如果要追加,在new FileWriter("文件名",true)设置
BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情况.txt",true));
//写入字符串
bw.write("姓名\t\t是否完成");
//换行
bw.newLine();
Scanner sc = new Scanner(System.in);
//随机3个人
for (int i = 0; i < 3; i++) {
String name = list.get(i);
System.out.println(name + "完成情况:");
String str = sc.next();
//写入读取到的内容
bw.write(name + "\t\t" + str);
//换行
bw.newLine();
}
bw.close();
}
}
ObjectOutputStream对象字节输出流(序列化)(掌握)
序列化:将对象转换为文件的过程
被序列化的对象,必须要实现Serializable接口。
这个接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化
构造方法
构造方法 | 说明 |
ObjectOutputStream(OutputStream os) | 创建一个对象字节输出流对象,参数为一个字节输出流对象,由于OutputStream是抽象类,所以使用其子类,如FileOutputStream对象,在其中定义要写入的文件 |
常用方法
常用方法 | 作用 |
writeObject(Object obj) | 将一个对象写入到本地文件中 |
close() | 关闭流对象 |
ObjectInputStream对象字节输入流(反序列化)(掌握)
反序列化:将文件转换为对象的过程
构造方法
常用构造方法 | 说明 |
ObjectInputStream(InputStream is) | 创建一个对象字节输入流对象,参数为一个字节输入流对象,由于InputStream是抽象类,所以使用其子类,如FileInputStream对象,在其中定义要读取的文件 |
常用方法
常用方法 | 作用 |
readObject() | 读取序列化后的文件,返回类型为Object |
close() | 关闭流对象 |
序列化和反序列化案例
Person类,实现Serializable接口
package com.hqyj.ObjectStream;
import java.io.Serializable;
/*
* 如果希望该类的对象能序列化,写入对象到本地,必须要实现Serializable接口
* Serializable接口中没有任何方法,是一个标记接口,表示该类的对象可以被序列化
* */
public class Person implements Serializable {
private String name;
private int age;
private String sex;
//省略getter/setter和toString()
}
Main类
package com.hqyj.ObjectStream;
import java.io.*;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person p1 = new Person("王海", 22, "男");
Person p2 = new Person("赵敏", 24, "女");
Person p3 = new Person("刘涛", 21, "女");
ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
//创建OutStream的实现类,设置写入的文件路径
OutputStream os = new FileOutputStream("F:\\221001\\person.p");
//创建对象输出字节流,参数为OutStream类型
ObjectOutputStream oos = new ObjectOutputStream(os);
//调用writeObject(Object obj)方法,将对象写入到硬盘中(序列化)
oos.writeObject(list);
oos.close();
//创建对象输入字节流,将上一步保存的文件进行反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:\\221001\\person.p"));
//使用readObject()方法,将写入的文件进行读取(反序列化)
ArrayList<Person> pList = (ArrayList<Person>) ois.readObject();
for (Person person : pList) {
System.out.println(person);
}
ois.close();
}
}
转换流
实际属于字符流,作用为将一个字节流对象转换为字符流对象
OutputStreamWriter
将字节输出流转换为字符输出流
InputStreamReader
将字节输入流转换为字符输入流
转换流的使用
如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。
使用字符流读写字符时比字节流更方便。
//假如只提供一个字节输出流对象
FileOutputStream fos = new FileOutputStream("文件路径");
//fos.write(97);//这时如果写入数据,只能按字节写入,不方便
//使用转换流,将字节流对象fos转换为字符流对象
Writer writer = OutputStreamWriter(fos);
//将字符流对象writer包装成缓冲字符流对象
BufferedWriter bw = new BufferedWriter(writer);
bw.write("hello你好");
bw.newLine();
bw.close();
//只提供字节输入流对象
FileInputStream fis = new FileInputStream("221001.txt");
// fis.read()每次只能读取一个字节
//将字节流转换为字符流
Reader reader = new InputStreamReader(fis);
//创建缓冲字符流,将字符流包装为缓冲流
BufferedReader br = new BufferedReader(reader);
//整行读取
while (br.ready()) {
System.out.println(br.readLine());
}
br.close();