1、什么是IO?
(1)I:Input
(2)O:Output
(3)通过IO可以完成硬盘文件的读写
2、IO流的分类
(1)按照流的方向:(以内存为参照物)
a.往内存中去,叫做输入(Input),或者叫读(Read)
b.从内存中出来,叫做输出(Output),或者叫写(Write)
(2)按照读取数据方式:
a.按照字节的方式读取数据,一次读取1个字节byte,等同一次读取8个二进制码,这种流是万能的,什么类型的文件都可以读取。【字节流】
b.按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件.txt而存在的。【字符流】
3、java中所有的流都在:java.io.*;下
4、IO流的类
(1)字节流【以Steam结尾】
a. java.io.InputStream
b. java.io.OutputStream
(2)字符流【以Reader和Writer结尾】
a. java.io.Reader
b. java.io.Writer
5、所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。【流是一个管道,是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。】
6、所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。输出流在最终输出之后,一定要记得flush()刷新一下,这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。
7、主要使用的流:
(1)文件专属
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileReader
java.io.FileWriter
(2)转换流:将字节流转换成字符流
java.io.InputStreamReader
java.io.OutputStreamWriter
(3)缓冲流专属
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInput
java.io.BufferedOutput
(4)数据流专属
java.io.DataInputStream
java.io.DataOutputStream
(5)标准输出流
java.io.PrintWriter
java.io.PrintReader
(6)对象专属流
java.io.ObjectInputStream
java.io.ObjectOutputStream
1、文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
2、字节的方式,完成输入的操作,完成读的操作。
FileInputStream fis = null;
try {
// 采用了绝对路径,D:/Windows/新建文本文档.txt 这种形式也可以
fis = new FileInputStream("D:\\Windows\\新建文本文档.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally{ // 在finally语句块中确保流一定关闭!
if(fis != null){
// 关闭前提:流不是null的时候关闭,避免空指针异常
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:IDEA中的默认路径(相对路径):Project的根
语法规则
// int available() // 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。 System.out.println(fis.available()); // 6,因为文本中只存储了6个英文字符
常用用法【一次性读取文件所有数据】
// 这种方法不适合太大的文件,因为byte[]数组不能太大 // 一次性读取文件所有数据 byte[] bytes = new byte[fis.available()]; fis.read(bytes); String s = new String(bytes); System.out.print(s);
语法规则
// long skip(long n) // 从输入流中跳过并丢弃 n 个字节的数据,并返回实际跳过的字节数 System.out.println(fis.skip(3));
read()
// read()方法读取一个字节,并返回其ASCII码 System.out.println(fis.read()); // 结果为97,因为第一个字符为a,其ASCII码为97
read(byte[] b)
// read(byte[] b)方法是将字节读入byte数组,并返回读入数组的字节数 System.out.println(fis.read(bytes)); // 4,因为定义的byte数组长度为4
int read(byte[] b, int off, int len) // 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中,并返回当前读入的字节数 int count = 0; while((count = fis.read(bytes)) != -1){ // 将文本中所有信息输出 //System.out.println(fis.read(bytes,0,count)); String s = new String(bytes,0,count); System.out.print(s); }
1、文件字节输出流,万能的,任何类型的文件都可以采用这个流来读
2、字节的方式,完成输出的操作,完成写的操作。
3、写完之后一定要刷新:flush()
第一种【会清空原有数据】
// 若是没有FileOutputStreamTest.txt文件,则会新建 // 这种方法谨慎使用,这种方式会先将源文件清空,然后重新写入 fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\FileOutputStreamTest.txt");
第二种【推荐】
FileOutputStream(String name, boolean append) name - 与系统有关的文件名 append - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处 // 以追加的方式,不会清空原文件内容 fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\FileOutputStreamTest.txt",true);
write(byte[] b)
// void write(byte[] b) // 将 b.length 个字节从指定 byte 数组写入此文件输出流中。 // 将bytes数组写入到文件中 fos.write(bytes);fos.flush();
write(byte[] b, int off, int len)
// void write(byte[] b, int off, int len) // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 fos.write(bytes,0,3);fos.flush();
write(int b)
// void write(int b) // 将指定字节写入此文件输出流。 fos.write(97);fos.flush();
1、带有缓冲区的字符输入流
2、使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓存
3、当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
4、外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流
5、对于包装流来说,只需要关闭最外层就行,里面的节点流会自动关闭
// 节点流 FileReader out = new FileReader("Test/src/IOTest/IOTest03/IOTest.java"); // 包装流 BufferedReader in = new BufferedReader(out);合并写法:
BufferedReader in = new BufferedReader(new FileReader("Test/src/IOTest/IOTest03/IOTest.java"));
作用:读取一个文本行,但不带换行符
System.out.println(in.readLine()); String nowLine = null; while((nowLine = in.readLine()) != null){ System.out.println(nowLine); }
用法参考BufferedReader
// 字节流 FileInputStream fis = new FileInputStream("Test/src/IOTest/IOTest03/IOTest.java"); // 通过转换流转换(将字节流转换为字符流) // in是节点流,isr是包装流 InputStreamReader isr = new InputStreamReader(fis); // isr是节点流,bfr是包装流 BufferedReader bfr = new BufferedReader(isr);合并写法:
BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("Test/src/IOTest/IOTest03/IOTest.java")));
1、需要用到内存,将数据从源硬盘处读取到内存中,再将内存中读到的数据写入目标硬盘中。【这个过程是一边读一边写】
// 输入文件流 fis = new FileInputStream("D:\\BaiduNetdiskDownload\\Java零基础教程\\动力节点Java零基础经典教程\\Java零基础四部曲\\第二部曲\\001-我们要学什么目标是啥.avi"); // 输出文件流 fos = new FileOutputStream("D:\\001-我们要学什么目标是啥.avi"); // 1MB(一次最多拷贝1MB) byte[] bytes = new byte[1024 * 1024]; // 核心:一边读一边写 int count = 0; while((count = fis.read(bytes)) != -1){ fos.write(bytes,0,count); } // 刷新,输出流最后要刷新 fos.flush();
1、用DataInputStream写的文件,只能用DataOutputStream去读,并且读的时候需要提前知道写入的顺序。读的顺序要和写的顺序一致,才能正常读出数据。
1、标准流不需要手动关闭,会自动关闭
1、System.out.println(“”);
2、PrintStream ps = System.out
ps.println("");
将输出指定到目标文件【一般作为日志工具】
System.setOut(new PrintStream(new FileOutputStream("文件目录")));
1、参与序列化和反序列化的对象,必须实现Serializable接口,这个接口中什么代码也没有,起到标识作用,使Java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。
2、Java虚拟机看到Serializalbe这个接口,会为该类自动生成一个序列化版本号
3、序列化版本号:
(1)java中区别类:首先类名对比,类名相同,比较序列化版本号
(2)自动序列化版本号:缺陷:源代码确定之后,不能修改,一旦修改,必然重新编译,此时会生成全新的序列化版本号,这时Java就认为是全新的类。
(3)建议自己手写序列化版本号:
private static final long serialVersioUID = 序列化版本号;
(4)IDEA工具自动化生成序列化版本号:File->Settings->Editor->Code Style->Inspections->搜索Serializable class without ‘serialVersionUID’
1、将内存中的Java对象的状态保存下来的过程。
2、ObjectOutputStream
3、单个对象实现序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student")); Student s = new Student("张三", "02111"); // 将Student对象写入 oos.writeObject(s); // 刷新 oos.flush(); // 关闭 oos.close();
4、多个对象实现序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student")); ListstuList = new ArrayList<>(); stuList.add(new Student("张三", "0211")); stuList.add(new Student("张三", "0212")); stuList.add(new Student("张三", "0213")); // 写入 oos.writeObject(stuList); // 刷新 oos.flush(); // 关闭 oos.close();
1、将硬盘上的数据重新恢复到内存中,恢复成Java对象。
2、ObjectInputStream
3、单个对象实现反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student")); // 获取对象 Object obj = ois.readObject; // 输出对象信息 System.out.println(obj); // 关闭 ois.close();
4、多个对象实现反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student")); // 获取List对象 ListstuList = (List )ois.readObject(); // 遍历List对象,输出每个Student对象信息 for(Student stu : stuList){ System.out.println(stu); } // 关闭 ois.close();
1、修饰成员变量,表示游离的,不参与序列化
(1)IO:文件的读和写
(2)Properties:是一个Map集合,key和value都是String类型
(1)将某个文件中的数据加载到Properties对象当中
(2)Java中经常变动的信息,可以单独写到一个文件中,使用程序动态读取,将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启,就可以拿到动态数据,这种文件被称为配置文件,当配置文件中内容格式为【key=value】时,称为属性配置文件。(3)java规范要求:属性配置文件要以properties结尾,但这不是必须的。Properties是专门存放属性配置文件内容的一个类。
(4)属性配置文件
a.key和value中不要有空格
错误:key = value
正确:key=value或key:value【不建议使用冒号】
b.#是注释符号
c.key重复,则value自动覆盖
// 新建一个输入流对象 FileReader reader = new FileReader("Test/src/IOTest/IOTest06/username"); // 新建一个Map集合 Properties pro = new Properties(); // 调用Properties中的load()方法将文件中的数据加载到Map集合中 pro.load(reader); // 通过key来获取value System.out.println(pro.getProperty("username")); System.out.println(pro.getProperty("password"));
1、Flie类不能完成读和写
2、File对象代表文件和目录路径名的抽象表示形式。一个File对象有可能是对应的目录也可能是文件。
File f1 = new File("C:/windows");
若目录存在,返回true,若不存在,返回false
f1.exists();
以文件形式新建
f1.createNewFile()
以目录形式新建
f1.mkdir()
以多重目录形式新建
f1.mkdirs()
获取文件的父路径
f1.getParent()
获取绝对路径
f1.getAbsolutePath()
获取文件名
f1.getName()
判断是否为目录
f1.isDirectory()
获取文件最后一次修改时间【返回毫秒数,是1970年到现在的毫秒数】
f1.lastModified()
获取文件大小
f1.length()
获取当前目录下的所有子文件【返回File类型数组】
f1.listFile()