什么是流?
概念:内存与存储设备之间传输数据的通道
流的分类
按方向:
- 输入流,将<存储设备>中的内存读入到<内存>中。
- 输出流,将<内存>中的内容写入到<存储设备>中。
按单位:
- 字节流:以字节为单位,可以读写所有数据。
- 字符流:以字符为单位,只能读写文本数据。
按功能:
- 节点流:具有实际传输数据的读写功能
- 过滤流:在节点流的基础上增强功能
字节流
字节流的父类(抽象类) 不可实例化
-
InputStream: 字节输入流(读)
- FileInputStream:public int read(byte[] b) //从流中读取多个字节,将读到的内容传递给b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1;
-
OutputStream:字节输出流(写)
- FileOutputStream:public void write (byte[] b) //一次写多个字节,将b数组中所有字节写入输入流
使用FileInputSream读取数据
//1.创建FileInputStream,并指定文件路径
FileInputStream fis = new FileInputStream("D:\\国家机密\\IO流\\aaa.txt");
//2.读取文件
//fis.read();
//2.1单个字节获取
// int data = 0;
// while((data = fis.read()) != -1){
// System.out.print((char) data);
// }
//2.2多个字节获取
byte[] buf = new byte[10];
int count = 0;
while ((count = fis.read(buf)) != -1){
//创建字符串对象 String str = new String("");
System.out.println(new String(buf,0,count));
}
//3.关闭
fis.close();
System.out.println("执行完毕");
//结果是
abcdefg
执行完毕
使用FileOutputSream写入数据
//1.创建文件字节输出流
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\bbb.txt");
//2.写入文件
fos.write(97);
fos.write(98);
fos.write(99);
//3.关闭
fos.close();
System.out.println("执行完毕");
//写入多个数据
String string = "HelloWorld";
//getbyte方法 获取字符串所对应的字节数
fos.write(string.getBytes());
//如果想要输入的信息是追加而不是覆盖 可在创建对象时添加true参数
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\bbb.txt",true);
复制文件
//1.创建流
//1.1文件字节输入流
FileInputStream fis = new FileInputStream("D:\\国家机密\\IO流\\1.jpg");
//1.2文件字节输出流
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\2.jpg");
int count = 0;
byte[] buf = new byte[1024];
while((count = fis.read(buf)) != -1){
fos.write(buf,0,count);
}
//3.关闭
fis.close();
fos.close();
System.out.println("复制完毕");
字节缓冲流 BufferedInputStream/BufferedOutputStream
- 提高IO效率,减少访问磁盘的次数
- 数据存储在缓冲区中,flush是将缓存区的内容写入文件中
使用BufferedInputSream读取数据
//1创建BufferedInputStream
FileInputStream fis = new FileInputStream("D:\\国家机密\\IO流\\aaa.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
//2读取
// int data = 0;
// while ((data = bis.read()) != -1){
// 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();
System.out.println("执行完毕");
使用BufferedInputSream写入数据
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\buffer.txt");
//1.创建字节输出缓冲流
BufferedOutputStream bos = new BufferedOutputStream(fos);
//2.写入文件
for (int i = 0;i<10;i++){
bos.write("HelloWorld".getBytes());
bos.flush();//刷新到硬盘 执行一半断电了数据还在
}
//3. 关闭(内部调用flush方法)
// bos.close();
// System.out.println("执行成功");
对象流
ObjectOutputStream/ObjectInputStream
- 增强了缓冲区的功能
- 增强了读写8种基本数据类型和字符串功能
- 增强了读写对象共功能
-
- readObject() 从流中读取一个对象
- writeObject(Object obj) 向流中写一个对象
使用流传输对象的过程称为序列化(写入文件)、反序列化(读取文件)。
序列化
//1.创建一个对象流
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\stu.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2.序列化(写入操作)
Student zhangsan = new Student("张三",20);
oos.writeObject(zhangsan);
//3.关闭
oos.close();
System.out.println("执行完毕");
//前提条件 对象必须实例化Seriallizable标记接口
public class Student implements Serializable
反序列化
//1.创建对象流
FileInputStream fis = new FileInputStream("D:\\国家机密\\IO流\\stu.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
//2.读取文件(反序列化)
Object obj = ois.readObject();
// Object obj2 = ois.readObject(); 只能读取一次否则报错
// Exception in thread "main" java.io.EOFException
//3.关闭
ois.close();
System.out.println("执行完毕");
System.out.println(obj.toString());
序列化与反序列化的注意事项
-
序列化类必须要实现Serializeable接口
public class Student implements Serializable
-
序列化类中对象属性要求实现 Serializeable接口
(类中如果再实例化一个类,那么这个类也必须实现接口)
-
序列化版本号ID,保证序列化的类和反序列化的类是同一个类
private static final long serialVersionUID = 100;//数值可随意填写 // ID不同 反序列化会报错 // Exception in thread "main" java.io.InvalidClassException //解决办法 1. 更改ID保持一致 2. 重新序列化
-
使用transient(意思:瞬间的)修饰属性,该属性就不会被序列化
private transient int age;
-
静态属性不可序列化
-
序列化多个对象
// 写入两个对象 Student zhangsan = new Student("张三",20); Student lisi = new Student("李四",21); //读取两次(麻烦) Object obj1 = ois.readObject(); Object obj2 = ois.readObject(); //第二种方法 //使用集合写入 ArrayList<Object> list = new ArrayList<>(); list.add(zhangsan); list.add(lisi); oos.writeObject(list); //读取一次(方便) Object obj1 = ois.readObject(); //或者 ArrayList<Object> list = (ArrayList<Object>) ois.readObject();
字符编码
- ISO-8859-1 收录除ASCII外,还包西欧,希腊语,泰语、阿拉伯语、希伯来语对应的文字符号
- UTF-8 针对Unicode码表的可变长度字符编码(1,2,3个字节表示字符,对于中文一个汉字三个字节)
- GB2312 简体中文(1,2个字节表示字符)
- GBK 简体中文、对于GB2312的扩充(1,2个字符表示)可编译ANSI文件
- BIG5 台湾 繁体中文
当编码方式和解码方式不一致时,会出现乱码
字符流
字符流父类
-
Reader
-
-
FileReader
public int read(char[] c) //从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部。则返回-1
-
-
Writer
-
-
FileWriter
public void write(String str) //一次写多个字符,将b数组中所有字符,写入输出流
-
使用FileReader读取文档
//1.创建FileReader 文件字符输入流
FileReader fr = new FileReader("D:\\国家机密\\IO流\\hello.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写入数据
//1.创建FileWriter对象
FileWriter fw = new FileWriter("D:\\国家机密\\IO流\\write.txt");
//2.写入
for (int i = 0;i<10;i++){
fw.write("java是世界上最好的语言\n");
fw.flush();
}
//3.关闭
fw.close();
System.out.println("执行完毕");
复制文件
//只能复制文本文件,不能复制图片或二进制文件(视频,音乐等都是以二进制存储的)因为没有字符编码
//1.创建FileReader
FileReader fr = new FileReader("D:\\国家机密\\IO流\\write.txt");
//2.创建FileWriter
FileWriter fw = new FileWriter("D:\\国家机密\\IO流\\write2.txt");
int data = 0;
while ((data = fr.read()) != -1){
fw.write(data);
fw.flush();
}
//3.关闭
fr.close();
fw.close();
System.out.println("执行完毕");
字符缓冲流 BufferedReader/BufferedWriter
- 高效读写
- 支持输入换行符
- 可一次写一行,读一行
BufferedReader读取文件
//1.创建字符缓冲流 BufferedReader
FileReader fr = new FileReader("D:\\国家机密\\IO流\\write.txt");
BufferedReader br = new BufferedReader(fr);
// //2.读取 第一种方式
// char[] buf = new char[1024];
// int count = 0;
// while ((count = br.read(buf)) != -1){
// System.out.println(new String(buf,0,count));
// }
//2.1按行读取 第二种方式 readLine() 获得一行的字符
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//3.关闭
br.close();
System.out.println("执行完毕");
BufferedWrite写入文件
//1.创建BufferedWriter
FileWriter fw = new FileWriter("D:\\国家机密\\IO流\\buffer.txt");
BufferedWriter bw = new BufferedWriter(fw);
// //2.写入
for (int i = 0; i < 10 ; i++){
bw.write("好好学习天天向上");
bw.newLine(); // 换行符
bw.flush();
}
//3.关闭
bw.close();
System.out.println("执行完毕");
打印流 PrintWriter
- 封装了print()/println()方法,支持写入后换行
- 支持数据原样打印
//1. 创建打印流
PrintWriter pw = new PrintWriter("D:\\国家机密\\IO流\\print.txt");
//2.打印
pw.println(97);
pw.println(true);
pw.println(3.14);
pw.println('a');
pw.println("a");
//3.关闭
pw.close();
System.out.println("打印完毕");
转换流(内存中的字符与硬盘中的字节转换)
桥转换流 InputStreamReader/OutputStreamWriter
- 可将字节流转换为字符流
- 可设置字符的编码方式
InputStreamReader读取文件
//1.创建InputStreamWriter对象
FileInputStream fis = new FileInputStream("D:\\国家机密\\IO流\\write.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");//读取文件,字符编码为GBK
//2.读取文件
int data = 0;
while ((data = isr.read()) != -1){
System.out.print((char)data);
}
//3.关闭
isr.close();
System.out.println("读取完毕");
OutputStreamWriter写入文件
//1.创建OutputStreamWriter
FileOutputStream fos = new FileOutputStream("D:\\国家机密\\IO流\\info.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");//写入文件,字符编码为GBK
//2.写入
for(int i = 0; i < 10; i++){
osw.write("我爱北京,我爱故乡\n");
osw.flush();
}
//3.关闭
osw.close();
System.out.println("写入完毕");
File类(1.分隔符 2.文件操作 3. 文件夹操作)
概念: 代表物理盘符中的一个文件或者文件夹
方法:
方法名 | 用 |
---|---|
mkdir() | 创建一个新目录 |
delete() | 删除文件或空目录 |
exists() | 判断File对象所代表的对象(文件)是否存在 |
getAbsolutePath() | 获取文件的绝对路径 |
getName() | 取得名字 |
getParent() | 获取文件/目录所再的目录 |
isDirectory() | 是否是目录 |
isFile() | 是否是文件 |
length() | 获得文件的长度 |
listFiles() | 列出目录中的所有内容 |
renameTo() | 修改文件名 |
分隔符
//(1) 分隔符
private static void separator() {
System.out.println("路径分隔符" + File.pathSeparator);
System.out.println("名称分隔符" + File.separator);
}
//输出结果
路径分隔符;
名称分隔符\
文件操作
//(2) 文件操作
//1.创建文件 createNewFile()
public static void fileOpe() throws Exception{
File file = new File("D:\\国家机密\\IO流\\file.txt");
//如果只写文件名不写路径 会在当前项目中创建文件
//创建一个文件对象 不是创建文件 文件不一定会创造出来
// System.out.println(file.toString());
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.getAbsoluteFile());
System.out.println("获取路径:" + file.getPath());
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());
}
//输出结果
获取文件的绝对路径:D:\国家机密\IO流\file.txt
获取路径:D:\国家机密\IO流\file.txt
获取文件名称:file.txt
获取父目录:D:\国家机密\IO流
获取文件长度:21
文件创建时间:2023年3月12日 下午5:04:50
是否可写true
是否是文件true
是否隐藏false
文件夹操作
//(3) 文件夹操作
public static void directoryOpe() throws Exception {
//1.创建文件夹
File dir = new File("D:\\国家机密\\IO流\\aa\\bb\\cc");
//System.out.println(dir.toString());
if (!dir.exists()){
boolean c = dir.mkdirs();
//mkdir 创建单级目录 mkdirs创建多级目录
System.out.println(c);
}
//2. 删除文件夹(注意只能删除空目录)
//2.1直接删除
// System.out.println("删除结果为:" + dir.delete());
//2.2 使用jvm删除
// dir.deleteOnExit();
// Thread.sleep(5000);
//3. 获取文件夹信息
System.out.println("获取文件夹的绝对路径:" + dir.getAbsoluteFile());
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.isFile());
System.out.println("是否隐藏" + dir.isHidden());
//5. 遍历文件夹
File dir2 = new File("D:\\国家机密\\IO流");
String[] files = dir2.list();
System.out.println("--------------------------------------");
for (String string : files){
System.out.println(string);
}
//输出结果为
获取文件夹的绝对路径:D:\国家机密\IO流\aa\bb\cc
获取路径:D:\国家机密\IO流\aa\bb\cc
获取文件夹名称:cc
获取父目录:D:\国家机密\IO流\aa\bb
获取创建时间:2023年3月12日 下午5:38:18
是否是文件false
是否隐藏false
--------------------------------------
1.jpg
2.jpg
aa
aaa.txt
bbb.txt
buffer.txt
file.txt
hello.txt
info.txt
IO流1.md
print.txt
stu.bin
write.txt
FileFilter接口
- public interface FileFilter
- boolean accept(File pathname)
- 当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中
File[] files2 = dir2.listFiles(new FileFilter() { //实例化FileFilter类
//listFiles 遍历返回文件
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".md")){ //如果文件后缀名为.md
return true;
}
return false;
}
});
for (File file : files2){ //遍历文件数组
System.out.println(file.getName());
}
案例1: 递归遍历文件夹
public static void main(String[] args) {
listDir(new File("D:\\国家机密")); //实例化File传递地址给listDir方法
}
public static void listDir(File dir){
File[] files = dir.listFiles(); //遍历文件夹赋值给files数组
System.out.println(dir.getAbsolutePath()); //输出文件的绝对路径
if (files!=null&&files.length>0){ //判断数组是否为空 且数组长度是否大于0
for (File file : files){ //遍历数组
if (file.isDirectory()) { //判断是否为文件夹
listDir(file); //递归遍历文件夹
}else {
System.out.println(file.getName()); //输出文件名
}
}
}
}
案例2:递归删除文件夹
//案例2 递归删除文件夹
public static void deleteDir(File dir) throws Exception{
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());
}