IO流
流的概念
内存与存储设备之间传输数据的通道
流的分类
按方向
- 输入流:将<存储设备>中的内容读到<内存>中 文件 --> 程序
- 输出流:将<内存>中的内容写到<存储设备>中 程序 --> 文件
按单位
- 字节流:以字节为单位,可以读写所有数据
- 字符流:以字符为单位,只能读写文本数据
按功能
- 节点流:具有实际传输数据的读写功能
- 过滤流:在节点流的基础之上增强功能
字节流
字节流的父类是两个抽象类,抽象类不能实例化,让子类去继承它,实例化它的子类
// InputStream 字节输入流:表示字节输入流的所有类的超类
public int read(){} // 从输入流中读取数据的下一个字节,返回 0 到 255 范围内的 int 字节值,读到最后返回-1
public int read(byte[] b){} //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中,返回读入缓冲区的总字节数,读到最后返回-1
public int read(byte[] b, int off, int len){} //将输入流中最多len个数据字节读入byte数组,从b[off]开始
// OutputStream 字节输出流: 表示字节输出流的所有类的超类
public void write(int b){} // 将指定的字节写入此输出流
public void write(byte[] b){} // 将b.length个字节从指定的 byte 数组写入此输出流
public void write(byte[] b, int off, int len){} // 将指定 byte 数组中从off开始的 len 个字节写入此输出流
文件字节流
文件输入流
public static void main(String[] args) throws Exception{
// 1 创建FileInputStream 并指定已经存在的文件的路径
FileInputStream fis = new FileInputStream("d:\\FileTest.txt");
//d:\\FileTest.txt内容 ABCDEFG
// 2 读取文件
// 2.1单字节读取
int data = 0;
while((data = fis.read()) != -1){ // data是相应的ascii值 int类型
System.out.println((char)data);
}
// 2.2 一次读取多个字节
byte[] buf = new byte[3]; // 大小为3的缓存区
int count = fis.read(buf); // 一次读3个
System.out.println(new String(buf));
System.out.println(count);
int count2 = fis.read(buf); // 再读3个
System.out.println(new String(buf));
System.out.println(count2);
// 上述优化后
int count1 = 0; //read()返回读入缓冲区的总字节数
while((count1 = fis.read(buf)) != -1){ //ABC
System.out.println(new String(buf, 0, count1)); //DEF
} //G
// 3 关闭
fis.close();
}
文件输出流
public static void main(String[] args) throws Exception{
// 1 创建文件字节输出流
FileOutputStream fos = new FileOutputStream("d:\\abc.txt", true);
// 如果文件不存在,自动创建该文件,true表示如果文件存在则不覆盖,追加内容,
// 2 写入文件
fos.write(97); // a的ascii值,会自动写入字符 a
fos.write('b');
fos.write('c');
String string = "hello world";
fos.write(string.getBytes());
// 3 关闭
fos.close();
}
文件复制案例
public static void main(String[] args) throws IOException {
// 1 创建流
// 1.1 文件字节输入流
FileInputStream fis = new FileInputStream("d:\\abc.txt");// jpg同理
// 1.2 文件字节输出流
FileOutputStream fos = new FileOutputStream("d:\\File.txt");
// 2 边读边写
byte[] buf = new byte[1024];
int count = 0;
while((count = fis.read(buf)) != -1){
fos.write(buf, 0, count);
}
// 3 关闭
fis.close();
fos.close();
}
字节缓冲流
缓冲流:BufferedInputStream/ BufferedOutputStream
- 提高IO效率,减少访问磁盘次数
- 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close也能将缓冲区的内容写入文件中
// 使用字节缓冲流读取文件
public static void main(String[] args) throws Exception{
// 1 创建BufferedInputStream
FileInputStream fis = new FileInputStream("d:\\abc.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
// 2 读取
int data = 0;
while((data = bis.read()) != -1){ // 缓冲区默认大小8*1024
System.out.println((char)data);
}
// 用自己创建的缓冲流
byte[] buf = new byte[1024];
int count = 0;
while((count = bis.read(buf)) != -1){
System.out.println(new String(buf, 0, count));
}
// 3 关闭
bis.close();
}
// 使用字节缓冲流写入文件
public static void main(String[] args) throws Exception {
// 1 创建BufferedInputStream
FileOutputStream fos = new FileOutputStream("d:\\bbb.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 2 写入文件
for (int i = 0; i < 4; i++) { // 循环读取仍使用同一个缓冲区
bos.write("hello\r\n".getBytes());// 写入同一个8k大小缓冲区
// \r\n换行
bos.flush(); // 刷新到磁盘
}
// 3 关闭(内部调用flush方法)
bos.close();
}
对象流
ObjectOutputStream / ObjectInputStream
-
增强了缓冲区功能
-
增强了读写8种基本数据类型和字符串的功能
-
增强了读写对象的功能
readObject()
从流中读取一个对象writeObject(Object obj)
向流中写入一个对象
-
使用流传输对象的过程称为序列化、反序列化
-
序列化:从内存中把对象写入存储设备
-
反序列化:从文件中读取对象 到内存
序列化
// 使用ObjectOutputStream实现序列化
public static void main(String[] args) throws IOException {
// 1. 创建对象流
FileOutputStream fos = new FileOutputStream("d:\\st.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 2. 序列化(写入操作)
Student zhangsan = new Student("zs", 20);
oos.writeObject(zhangsan);
// 3. 关闭
oos.close();//内含有flush()方法
System.out.println("序列化完毕");
}
反序列化
// 使用ObjectInputSteam实现反序列化(读取重构对象)
public static void main(String[] args) throws Exception {
// 1. 创建对象流
FileInputStream fis = new FileInputStream("d:\\st.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
// 2. 读取文件(反序列化)
Student s = (Student)ois.readObject(); //默认返回Object类型
// 3. 关闭
ois.close();
System.out.println("执行完毕");
System.out.println(s.toString());
}
注意事项
- 某个类要想序列化必须实现Serializable接口
- 序列化类中的作为属性的对象的类也要求实现Serializable接口
- 序列化版本号ID(private static final long serialVersionUID),保证序列化的类和反序列化的类是同一个类
- 使用transient(短暂的)修饰属性,这个属性就不能被序列化,也就是不能被保存到硬盘,将对象写入再读取会发现属性成为了类型默认值
- 静态属性不能序列化,也就是不能被保存到硬盘
- 序列化多个对象,可以包装成集合类实现
编码方式
- ISO-8859-1,使用一个字节最多表示256个字符
- GBK使用1、2个字节表示
- UTF-8 针对Unicode码表的可变长度字符编码,使用1、2、3个字节表示,单个汉字使用3字节
- 编码和解码的方式不一致会出现乱码
字符流
字符流的父类(抽象类)
Reader
字符输入流
public int read(){}
读取一个字符public int read(char[] c){}
public int read(char[] b, int off, int len){}
Writer
字符输出流
-
public void write(int n){}
写入一个字符 -
public void write(String str){}
写入一个字符串 -
public void write(char[] c){}
写入一个字符数组
FileReader使用
public static void main(String[] args) throws Exception {
// 1. 创建FileReader 文件字符输入流 (记事本创建时默认格式必须是UTF-8,尽量先写入再读取)
FileReader fr = new FileReader("d:\\hell.txt");
// 2. 读取
// 2.1 单个字符读取
int data = 0;
while((data = fr.read()) != -1){
System.out.print((char)data);// 读取一个字符,空格也算字符
}
char[] buf = new char[2];// 字符缓冲区读取
int count = 0;
while((count = fr.read(buf)) != -1){
System.out.println(new String(buf, 0,count));
}
//3. 关闭
fr.close();
}
FileWriter使用
public static void main(String[] args) throws Exception{
// 1. 创建FileWriter对象
FileWriter fw = new FileWriter("d:\\hell.txt",true);
// 2. 写入
for(int i = 0; i < 1; i ++){
fw.write("字符串");
fw.write('a');
char[] chars={'a','b','c'};
fw.write(chars);
fw.flush(); //有缓冲区
}
// 3. 关闭
fw.close();
System.out.println("执行完毕");
}
文本文件复制
只能复制文本文件,不能复制图片(没有字符编码)或二进制文件,使用字节流可以复制任意文件
public static void main(String[] args) throws Exception{
// 1. 创建
FileReader fr = new FileReader("d:\\hell.txt");
FileWriter fw = new FileWriter("d:\\hell2.txt");
// 2. 读写
int data = 0;
while((data = fr.read()) != -1){
fw.write(data);
fw.flush();
}
// 3. 关闭
fw.close();
fr.close();
}
字符缓冲流
BufferedReader / BufferedWriter
高效读写;支持输入换行符;可一次写一行、读一行
public static void main(String[] args) throws Exception{
// 创建缓冲流
FileReader fr = new FileReader("d:\\hello.txt");
BufferedReader br = new BufferedReader(fr);
// 读取
// 1. 第一种方式
char[] buf = new char[222];
int count = 0;
while((count = br.read(buf)) != -1){
System.out.println(new String(buf, 0, count));
}
// 2. 第二种方式 一行一行读取
String line = null;
while((line = br.readLine()) != null){
System.out.println(line);
}
// 关闭
br.close// 此时会自动关闭fr
}
public static void main(String[] args) throws IOException {
// 1. 创建BufferedWriter对象
FileWriter fw = new FileWriter("d:\\hello.txt");
BufferedWriter bw = new BufferedWriter(fw);
// 2. 写入
for(int i = 0; i < 2; i ++){
bw.write("写入的内容");
bw.newLine(); // 写入一个换行符
bw.flush();
}
// 3. 关闭
bw.close(); // 此时会自动关闭fw
}
PrintWriter
-
封装了
print() / println()
方法,支持写入后换行 -
支持数据原样打印
public static void main(String[] args){
// 1 创建打印流
PrintWriter pw = new PrintWriter("d:\\print.txt");
// 2 打印
pw.println(true);
pw.println(3.14);
pw.println('a');
pw.println(12); // int类型
// 3 关闭
pw.close();
}
转换流
桥转换流 InputStreamReader / OutputStreamWriter
-
字节流(硬盘)<===>字符流(内存)
-
可设置字符的编码方式
public static void main(String[] args) throws Exception{
// 1 创建InputStreamReader对象
FileInputStream fis = new FileInputStream("d:\\hello.txt");
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
// 文件编码与此处指定编码必须一致
// 2 读取文件
int data = 0;
while((data = isr.read()) != -1){ // 读取单个字符
System.out.print((char)data);
}
// 3 关闭
isr.close();
}
public static void main(String[] args) throws Exception{
// 1 创建OutputStreamReader对象
FileOutputStream fos = new FileOutputStream("d:\\osw.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
// 若文件不存在,此处指定编码就是文件编码;若文件存在,将文件编码改为此指定编码
// 2 写入
for(int i = 0; i < 3; i ++){
osw.write("写入内容"); // 写入字符串
osw.flush();
}
// 3 关闭
osw.close();
}
File类
概念:代表物理盘符中的一个文件或者文件夹
常用方法:
方法名 | 解释 |
---|---|
createNewFile() | 创建一个新文件 |
mkdir() | 创建一个新目录 |
delete() | 删除文件或空目录 |
exists() | 判断文件或文件夹是否存在 |
getAbsolutePath() | 获取文件的绝对路径 |
getName() | 获取文件名,注意会带文件后缀 |
getParent() | 获取文件/目录所在的目录 |
isDirectory() | 判断是否是目录 |
isFile() | 是否为文件 |
length() | 获取文件的长度 |
listFiles() | 列出目录中的所有内容 |
renameTo() | 修改文件名为 |
deleteOnExit() | jvm退出后删除文件(夹) |
canWrite() | 判断文件是否可写入 |
分隔符
public class FileTest {
public static void main(String[] args){
separator();
}
// 分隔符
public static void separator(){
System.out.println("路径分隔符" + File.pathSeparator);// 路径分隔符;
System.out.println("名称分隔符" + File.separator);// 名称分隔符\
}
}
文件操作
// 文件操作
public static void main(String[] args) throws IOException, InterruptedException {
// 1 创建文件
File file=new File("d:\\csb.txt");
// 只是创建了文件对象,文件是否存在不一定
if(!file.exists()){ // 是否存在
boolean b = file.createNewFile();
System.out.println("是否创建成功:"+b);
}
// 2 删除文件
// 2.1 直接删除
System.out.println("是否删除"+file.delete());
// 2.2 使用jvm退出时删除
file.deleteOnExit();
Thread.sleep(5000); // 休眠5秒
// 3 获取文件信息
System.out.println("获取绝对路径" + file.getAbsolutePath());//返回绝对路径
System.out.println("获取路径" + file.getPath());// 返回创建file对象时传入的路径
System.out.println("获取文件名称" + file.getName());
System.out.println("获取父目录" + file.getParent());
System.out.println("获取文件长度" + file.length()); // 返回字节数
System.out.println("文件创建时间" + new Date(file.lastModified())
.toLocaleString()) ;
// 4 判断
System.out.println("是否可写" + file.canWrite());
System.out.println("是否是文件" + file.isFile());
System.out.println("是否隐藏" + file.isHidden());
}
文件夹操作
public static void main(String[] args) throws Exception{
// 1. 创建文件夹
File dir = new File("d:\\test\\aaa\\ccc");
// 只是创建文件夹对象,文件夹是否存在不一定
System.out.println("文件夹名字:"+dir.toString());
if(!dir.exists()){
//boolean b = dir.mkdir(); // 只能创建单级目录
boolean b=dir.mkdirs(); // 创建多级目录
System.out.println("是否创建成功:"+b);
}
// 2. 删除文件夹
// 2.1 直接删除
dir.delete(); // 只能删除最底层空目录
// 2.2 使用jvm删除
dir.deleteOnExit(); // 只能删除最底层空目录
// 3. 获取文件夹信息(文件夹长度返回值是不确定)
System.out.println("获取绝对路径" + dir.getAbsolutePath());
System.out.println("获取路径" + dir.getPath());
System.out.println("获取文件夹名称" + dir.getName());
System.out.println("获取父目录" + dir.getParent());
System.out.println("文件夹创建时间" + new Date(dir.lastModified()) .toLocaleString());
// 4. 判断
System.out.println("是否是文件夹" + dir.isDirectory());
System.out.println("是否隐藏" + dir.isHidden());
System.out.println("--------------");
// 5. 遍历文件夹
File dir2 = new File("C:\\");
String[] files = dir2.list();
for(String str : files){
System.out.println(str);
}
}
FileFilter接口(文件过滤器)
public interface FileFilter {
boolean accept(File pathname);
}
public static void main(String[] args) {
File dir=new File("C:\\Program Files (x86)\\Tencent\\Qzone");
File[] files2 = dir.listFiles(new FileFilter(){
@Override
public boolean accept(File pathname){
if(pathname.getName().endsWith(".dll")){
return true;
}
return false;
}
});
for(File file : files2){
System.out.println(file.getName());
}
}
递归遍历文件夹
public static void main(String[] args) {
listDir(new File("d:\\test"));
}
public static void listDir(File dir){
File[] files = dir.listFiles();
System.out.println(dir.getAbsolutePath());
if(files != null && files.length > 0){
for(File file : files){
if(file.isDirectory()){
listDir(file); // 递归
}else {
System.out.println(file.getAbsolutePath());
}
}
}
}
递归删除文件夹
public static void main(String[] args) {
deleteDir(new File("d:\\test"));
}
public static void deleteDir(File dir){
File[] files = dir.listFiles();
if(files != null && files.length > 0){
for(File file : files){
if(file.isDirectory()){
deleteDir(file); // 递归
}else{
// 删除文件
System.out.println(file.getAbsolutePath() + "删除" + file.delete());
}}}
System.out.println(dir.getAbsolutePath() + "删除" + dir.delete());
// 删除文件夹
}
Properties
- 持久的属性集合,线程安全的集合,继承HashTable,可保存在流中或从流中加载。
特点:
- 存储属性名和属性值(键值对)。
- 属性名和属性值都是字符串类型。
- 没有泛型。
- 和流有关。
示例代码:
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("name", "csb");
properties.setProperty("age", "23");
// keySet() || entrySet()
Set<String> strings = properties.stringPropertyNames();
//返回此属性列表中的键集
for (String string : strings) {
System.out.println("Key:"+string+";"+
properties.getProperty(string));
}
// 输出
PrintWriter printWriter = new
PrintWriter("d:\\Properties.txt");
properties.list(printWriter);
// 将属性列表输出到指定的输出流。
printWriter.close();
// 保存
FileOutputStream fileOutputStream =
new FileOutputStream ("d:\\PropertiesStore.properties");
properties.store(fileOutputStream, "属性列表的描述");
// 属性列表(键值对)写入输出流
fileOutputStream.close();
// 读取
Properties properties1=new Properties();
FileInputStream fis=
new FileInputStream("d:\\PropertiesStore.properties");
properties1.load(fis);
//从输入流中读取属性列表(键值对)。
fis.close();
System.out.println(properties1.toString());
}
Properties.txt内容:
-- listing properties --
age=23
name=csb
PropertiesStore.properties内容:
#\u5C5E\u6027\u5217\u8868\u7684\u63CF\u8FF0
#Tue Jul 06 13:58:58 CST 2021
age=23
name=csb