一些关于IO流的知识点
IO操作
Flie类
-
介绍:
File对象表示路径,可以是文件、也可以是文件夹。
这个路径可以是存在的,也可以是不存在的
绝对路径是带盘符的。相对路径是不带盘符的,默认到当前项目下去找
-
File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象:
- 通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
File(File parent, String child); File(String parent,String child);
- 把字符串表示的路径
File(String pathname) ;
-
创建File对象成功后,可以使用以下列表中的方法操作文件。
- public String getName():返回由此抽象路径名表示的文件或目录的名称。
- public String getPath():将此抽象路径名转换为一个路径名字符串。
- public boolean canRead():测试应用程序是否可以读取此抽象路径名表示的文件。
- public boolean canWrite():测试应用程序是否可以修改此抽象路径名表示的文件
- public boolean exists():测试此抽象路径名表示的文件或目录是否存在
- public boolean isDirectory():测试此抽象路径名表示的文件是否是一个目录。
- public boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件
- public long lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。
- public boolean mkdir():创建此抽象路径名指定的目录。
- public boolean renameTo(File dest): 重新命名此抽象路径名表示的文件
- public boolean setReadOnly():标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。
-
createNewFile 创建一个新的空的文件
- 如果当前路径表示的文件是不存在的,则创建成功,方法返回true,如果当前路径表示的文件是存在的,则创建失败,方法返回false
- 如果父级路径表示的文件是存在的,那么方法会有异常IOException
- createNewFile方 法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件。
-
mkdirs 创建多级文件夹
- windows当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false
- midir方法只能创建单级文件夹,无法创建多级文件夹。
- midirs既可以创建单级文件夹,也可以创建多级文件夹。
-
delete方法
- 如果删除的是文件,则直接删除,不走回收站
- 如果删除的是空文件夹,则直接删除,不走回收站。
- 如果删除的是有内容的文件,则删除失败。
-
listFiles()方法
- 当调用者File表示的路径不存在时,返回null
- 当调用者File表示的路径时文件时,返回null
- 当调用者File表示的路径时一个空文件时,返回一个长度为0的数组
- 当调用者File表示的路径时一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中放回
- 当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
- 当调用者File表示的路径时需要权限才能访问的文件夹时,返回null
IO流
-
IO的初步了解
-
什么是io流
存储和读取数据的解决方案
I:input O : output
-
IO流的作用?
用于读写数据(本地文件,网络)
-
IO流按照流向可以分类哪两种流?
输出流:程序-> 文件
输入流:文件-> 程序
-
IO流按照操作文件的类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
-
什么是纯文本文件?
用windows系统自带的记事本打开并且能够读懂的文件
txt文件,md文件,xml文件,lrc文件等
纯文本文件可以使用字符流去读取操作,而非纯文本文件如word,excel文件不能使用字符流,需要使用字节流。
-
-
字节输出流的细节
- 创建字节输出流对象
- 参数是字符串表示的路径或者是File对象都是可以的
- 如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
- 如果文件已经存在,则会清空文件
- 写数据:
- write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
- 释放资源:
- 每次使用完流之后都要释放资源,解除资源的占用
- 创建字节输出流对象
-
字节输入流的细节:
- 创建字节输入流对象
- 如果文件不存在,就直接报错
- 写数据
- 一次读一个字节,读出来的是数据在ASCII上对应的数字’
- 读到文件末尾了,read方法返回-1
- 释放资源
- 每次使用完流之后都要释放资源,解除资源占用
- 创建字节输入流对象
-
copy大文件时
public class ByteStreamDemo3 { public static void main(String[] args) throws IOException { FileInputStream fileInputStream = new FileInputStream("D:\\BaiduNetdiskDownload\\视频.mp4"); FileOutputStream fileOutputStream = new FileOutputStream("data/copy.mp4"); int len ; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fileInputStream.read(bytes))!=-1){ fileOutputStream.write(bytes,0,len); } fileOutputStream.close(); fileInputStream.close(); } }
-
如何不产生乱码?
- 不要用字节流读取文本文件
- 编码解码时使用同一个码表,同一个编码方式
-
字符流读取
- 空参读取
- 默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个,在读取之后,方法的底层还会进击解码并转成十进制
- 有参读取
- 读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中。相当于空参的read+强转类型转换。
- 空参读取
-
字节流和字符流的使用场景
- 字节流:
- 拷贝任意类型的文件
- 字符流:
- 读取纯文本文件中的数据
- 往纯文本文件中写出数据
- 字节流:
-
实列从一个文件夹拷贝到另一个文件夹
public class test1 { public static void main(String[] args) throws IOException { File src = new File("D:\\兰智数加\\aaa\\src"); File dest = new File("D:\\兰智数加\\aaa\\dest"); copydir(src,dest); } private static void copydir(File src, File dest) throws IOException { dest.mkdirs(); // 1.进入数据源 File[] files = src.listFiles(); // 2.遍历数组 for (File file : files) { //3.判断是否为文件,然后拷贝 if(file.isFile()){ FileInputStream fileInputStream = new FileInputStream(file); FileOutputStream fileOutputStream = new FileOutputStream(new File(dest, file.getName())); byte[] bytes = new byte[1024]; int len; while ((len=fileInputStream.read(bytes))!=-1){ fileOutputStream.write(bytes,0,len); } fileOutputStream.close(); fileInputStream.close(); }else { //4.判断是否为文件夹,然后递归 copydir(file,new File(dest,file.getName())); } } } }
-
缓冲流
- 缓冲流有几种?
- 字节缓冲输入流:BufferedInputStream
- 字节缓冲输出流:BufferedOutputStream
- 字符缓冲输入流:BufferedReader
- 字符缓冲输出流:BufferedWriter
- 缓冲流为什么能提高性能
- 缓冲流自带长度为8192的缓冲区
- 可以显著提高字节流的读写性能
- 对于字符流提升不明显,对于字符缓冲流而言关键点是两个特有的方法
- 字符缓冲流两个特有的方法是什么?
- 字符缓冲输入流 readLine()
- 字符缓冲输出流newLine()
下面是一个缓冲流的简单应用
import java.io.*; public class BufferedStreamDemo1 { /*TODO 节约的时间是在读和写时与硬盘打交道的时间 */ public static void main(String[] args) throws IOException { // 创建缓冲流读取数据 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("data/a.txt")); // 创建缓冲流写出数据 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("data/copy.txt")); int readLine; while ((readLine = bis.read()) != -1){ bos.write(readLine); } bos.close(); bis.close(); } }
- 缓冲流有几种?
-
转换流
在 Java 中,转换流主要用于在字节流和字符流之间进行转换。常用的转换流类有
InputStreamReader
和OutputStreamWriter
。这些类提供了将字节流转换为字符流,或者将字符流转换为字节流的功能。这对于处理不同编码格式的数据特别有用。// 这是一个简单转换流应用 import java.io.*; public class ConvertStreamDemo1 { public static void main(String[] args) throws IOException { // 创建字节输入流读取数据 FileInputStream fileInputStream = new FileInputStream("data/GBKfileText.txt"); // 创建转换流 读取GBK文件的内容 InputStreamReader isr = new InputStreamReader(fileInputStream, "GBK"); // 创建缓冲流 BufferedReader br = new BufferedReader(isr); // 创建字节输出流写出数据 FileOutputStream fileOutputStream = new FileOutputStream("data/GBKfile.txt"); // 创建转换流写出GBK文件 OutputStreamWriter osw = new OutputStreamWriter(fileOutputStream, "GBK"); // 创建缓冲流 BufferedWriter bw = new BufferedWriter(osw); // 读取数据并写出到新的地址 String line; while ((line = br.readLine()) != null){ bw.write(line); bw.newLine(); } bw.close(); br.close(); } }
-
序列化流
序列化流在 Java 中用于将对象的状态转换为字节流,以便可以将对象的状态保存到文件中、通过网络传输或存储在数据库中。反之,反序列化流则用于将字节流恢复为对象。
序列化是将对象的状态转换为字节流的过程,反序列化是将字节流恢复为对象的过程。在 Java 中,序列化是通过实现
Serializable
接口来实现的。- ObjectOutputStream:用于将对象写入输出流(序列化)。
- ObjectInputStream:用于从输入流读取对象(反序列化)。
下面是一个简单的应用:
# 创建一个标准的Student类 import java.io.Serializable; /** * Serializable接口里面没有抽象方法,是标记型接口 * 一旦实现这个接口,那么就表示当前的Student类可以被序列化 * 理解: * 可以是一个物品的合格证 */ public class Student implements Serializable { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public Student(){} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; }
# 创建一个序列化流把文件写道本地 import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectStreamDemo1 { public static void main(String[] args) throws IOException { /* 需求: 利用序列化流/对象操作输出流,把一个对象写本地文件中 构造方法: public ObjectOutputStream(OutputStream out)把基本流变成高级流 成员方法: public final void writeObject(Object obj) 把对象序列化(写出)到文件中去 */ // 创建对象 Student student = new Student("EzReal", 23); // 创建序列化流的对象/对象操作输出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data/a.txt")); // 写出数据 oos.writeObject(student); // 释放资源 oos.close(); } }
# 创建一个反序列化流读取文件 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectStreamDemo2 { public static void main(String[] args) throws IOException, ClassNotFoundException { // 创建反序列化流的对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data/a.txt")); // 读取数据 Object o = ois.readObject(); // 打印对象 System.out.println(o); // 释放资源 ois.close(); } }
序列化流/反序列化流的细节汇总
- 使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。否则,会出现notSerializableException异常
- 序列化流写到文件中的数据是不能被修改的,一旦修改了就无法再次读取回来了
- 序列化对象后,修改了JavaBean类,再次反序列化,会不会有问题?
- 会出问题,会抛出InvalidClassException异常
- 解决方案:给javabean类添加SerialVersionUID(序列号、版本号)
- 如果一个对象的某个成员变量的值不想被序列化,又该怎么实现呢?
- 解决方案:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
使用序列化流一次读取多个对象
// 序列化流 import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectStreamTestOutput { public static void main(String[] args) throws IOException { Student stu1 = new Student("zhangsan", 21, "nanjin"); Student stu2 = new Student("lisi", 22, "shanghai"); Student stu3 = new Student("wangwu", 23, "shenzhen"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data/a.txt")); oos.writeObject(stu1); oos.writeObject(stu2); oos.writeObject(stu3); oos.close(); } }
// 反序列化流 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; public class ObjectStreamTestInput { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data/a.txt")); ArrayList<Student> stuList = new ArrayList<>(); try { while (true){ Student stu = (Student)ois.readObject(); stuList.add(stu); } }catch (Exception e){ System.out.println("文件已经读取到末尾,开始打印数据:"); } System.out.println(stuList); ois.close(); } }