参考视频:https://www.bilibili.com/video/BV1Tz4y1X7H7?p=12
参考文档:https://www.cnblogs.com/coderzjz/p/13670088.html
目录
过滤输入输出流(可以代替FileInputStream和FileOutputStream):
字符缓冲流(是字符流的升级版,可以将数据部分放到缓冲区提高效率):
Java 的IO操作
java中的IO是input和output的缩写,是java中的传统的输入输出,下边有常见的用法。
流的分类:
按照数据流向区分流:
IO stream是 内存和存储设备(硬盘)之间的传输通道。
Input stream 输入流,将硬盘中的数据,读入到内存中。
Output stream 输出流,将内存中的数据,放到硬盘中。
按存储单位区分流:
字节流:以字节为单位,可以读写所有数据。
字符流:以字符为单位,只能读写文本数据。
按照功能区分流:
节点流:具有实际传输数据的读写功能。
过滤流:在节点流的基础之上增强功能。
IO的字节流:
InputStream 是抽象类,需要具体子类来实现(节点流):
AudioInputStream , ByteArrayInputStream , FileInputStream , FilterInputStream , InputStream , ObjectInputStream , PipedInputStream , SequenceInputStream , StringBufferInputStream
OutputStream 是抽象类,需要具体的子类实现
ByteArrayOutputStream , FileOutputStream , FilterOutputStream , ObjectOutputStream , OutputStream , PipedOutputStream
文件输入输出流:
FileInputStream read()函数,表示读取下一个字节 close()关闭输入流
FileOutputStream write()函数,从内存往硬盘写入下一个字节 close()关闭输出流
package io_nio.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileInputOutputStream {
public static void main(String[] args) throws IOException {
FileInputOutputStream test = new FileInputOutputStream();
test.readByteOneByOne();
test.readAsArray();
test.writeAsArray();
test.copyPictures();
}
// 一次读取一个字节
private void readByteOneByOne() throws IOException {
// 创建输入流,建立
FileInputStream inputStream = new FileInputStream("D:\\WorkCode\\LeetCodeDemo\\ioinputTemp.txt");
// 一个字节一个字节读入,会转成ASCII编码,然后强转成int型进行输出
// 如果希望用字符输出,可以强转成char即可(不支持中文)
int data = 0;
while ((data = inputStream.read()) != -1) {
System.out.print((char) data);
}
// 关闭流
inputStream.close();
}
// 按照数组的大小读取
private void readAsArray() throws IOException {
FileInputStream inputStream = new FileInputStream("D:\\WorkCode\\LeetCodeDemo\\ioinputTemp.txt");
// 用数组的形式,三个值进行一次读取,返回值是读取了多少字符
// 通常情况下都直接定义1024个字节的数组进行读取
byte[] buf = new byte[3];
int count = 0; //读取了多少个字符
while ((count = inputStream.read(buf)) != -1) {
System.out.print(new String(buf));
}
// 关闭流
inputStream.close();
}
// 写入数据 单个写入和按照byte[]写入
private void writeAsArray() throws IOException {
// 定义输出流,append表示是否继续写入,true表示持续写入,false和不写表示覆盖写入
FileOutputStream outputStream = new FileOutputStream("D:\\WorkCode\\LeetCodeDemo\\iooutputTemp.txt", true);
// 写入数据
// 输入的是ASCII码(或者char转换成ASCII码),写入硬盘的时候,会自动转成char
outputStream.write(97);
outputStream.write('b');
// 写入数据,可以按照byte数组往里写入
String string = "Hello world!";
byte[] chars = string.getBytes();
outputStream.write(chars);
outputStream.close();
}
private void copyPictures() throws IOException {
FileInputStream fileInputStream = new FileInputStream("D:\\WorkCode\\LeetCodeDemo\\van.jpg");
// 正常需要判断文件是否存在,如果存在了,就不能再追加写了
FileOutputStream fileOutputStream = new FileOutputStream("D:\\WorkCode\\LeetCodeDemo\\van_copy.jpg", true);
byte[] bytes = new byte[512];
int count = 0;
while ((count = fileInputStream.read(bytes)) != -1) { // 读取
fileOutputStream.write(bytes, 0, count); // 写出
}
fileInputStream.close();
fileOutputStream.close();
}
}
过滤输入输出流(可以代替FileInputStream和FileOutputStream):
FilterInputStream/FilterOutputStream 实例化了InputStream和OutputStream,并且覆盖了几乎所有的方法,其子类BufferedInputStream和BufferedOutputStream则是面向缓冲区的输入输出流。
相比于FileInputStream和FileOutputStream,这种方式将大量数据进行读入,并在缓存里进行操作,效率提高了。
package io_nio.io;
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.Buffer;
/**
* 使用字节缓冲流,再输入输出的时候不一段一段读取,而是将大量数据写入缓存,在缓存中进行读取
* <p>
* 提高IO效率,减少访问磁盘次数
* 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close
*/
public class BufferInputOutput {
public static void main(String[] args) throws IOException {
BufferInputOutput bufferInputOutput = new BufferInputOutput();
bufferInputOutput.bufferedInput();
bufferInputOutput.bufferedOutPut();
}
// BufferedInputStream 读取文件
// 使用这种文件读取的方式,相比于直接使用FileInputStream,读取的速度更快(文件已经被默认被存入缓冲区了)
// 之前使用char[]读取FileInputStream也相当于设定了一个缓冲区
// 关闭的时候只关闭bufferedInputStream即可
private void bufferedInput() throws IOException {
// 需要先传入一个底层节点流,在使用Buffered接住节点流
FileInputStream fileInputStream = new FileInputStream("D:\\WorkCode\\LeetCodeDemo\\ioinputTemp.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int count = 0;
byte[] buf = new byte[512];
while ((count = bufferedInputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, count)); //只将读取部分的数组初始化
}
// 关闭流数据
bufferedInputStream.close();
}
// 文件写入流,写入到指定的文件中
private void bufferedOutPut() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\WorkCode\\LeetCodeDemo\\iooutputTemp.txt", true);
BufferedOutputStream bufferedInputStream = new BufferedOutputStream(fileOutputStream);
String string = "hello world";
for (int i = 0; i < 10; i++) {
bufferedInputStream.write(string.getBytes()); //在BufferedOutputStream的默认缓冲区里,如果没有超过8k是不会写入的
}
bufferedInputStream.flush(); // 刷新一次,将数据从内存写入硬盘
bufferedInputStream.close();
}
}
对象输入输出流: 针对对象的读和写(序列化和反序列化)
这种依然是在缓冲区进行的操作,不过可以针对对象完成操作。即完成序列化和反序列化!
序列化和反序列化需要注意的事项:
1. 必须要实现Serializable接口
2. 序列化的类里包含的类属性也必须要实现Serialize接口
3. 序列化和反序列化必须保证是一个类,通常会使用serialVersionUID这个静态Strng字段完成校验
4. 使用transient来修饰序列化时候不序列化的属性(防止敏感信息泄露)
5. 静态的属性不能被序列化
package ioNio;
import java.io.*;
/**
* 针对对象的读入和写出 其实就是序列化和反序列化
* 序列:java的字节或者字符组成的一串字符
* 序列化:将Java的对象转换成一串文字,由内存转移到硬盘中进行存储
* 反序列化:将一串文字转换成Java的对象,由硬盘转移到内存中
* 注意:序列化和反序列化的类一定要实现Serializable这个接口
*/
public class ObjectInputOutputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputOutputStream objectInputOutputStream = new ObjectInputOutputStream();
objectInputOutputStream.objectOutputStream();
objectInputOutputStream.objectInputStream();
}
// 把硬盘中的数据反序列化成对象
private void objectInputStream() throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream("F:\\Codes\\LeetCode\\src\\tempfile\\objectFile.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
// 读取文件,反序列化
Student peter = (Student) objectInputStream.readObject();
objectInputStream.close();
System.out.println("Deserialization success!");
System.out.println(peter.toString());
}
// 把一个对象序列化到硬盘
private void objectOutputStream() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("F:\\Codes\\LeetCode\\src\\tempfile\\objectFile.txt");
ObjectOutputStream oos = new ObjectOutputStream(fileOutputStream);
Student peter = new Student("peter", 30);
oos.writeObject(peter);
oos.close();
System.out.println("Serialization success!");
}
}
/**
* 如果想要序列化,就必须要实现Serializable这个接口,其内部没有任何方法,只需要实现即可满足序列化和反序列化
*/
class Student implements Serializable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return this.name + " : " + age;
}
}
IO的字符流:
Reader:是抽象类,需要具体子类来实现(字符流父类):
BufferedReader , CharArrayReader , FilterReader , InputStreamReader , PipedReader , StringReader
Writer:是抽象类,需要具体的子类实现
BufferedWriter , CharArrayWriter , FilterWriter , OutputStreamWriter , PipedWriter , PrintWriter , StringWriter
这种读入的方式,是每一个字节进行读和写,虽然可以对所有的文件进行读写,但是如果使用了中文汉字,一个字占用了3个字节,基本就会出现乱码,这种情况就需要使用字符流 ,按照编码格式,一个字符一个字符进行读取。
文件输入输出流:
FileReader 是InputStreamReader的子类型,实际使用的类 read()函数,表示读取下一个字节 close()关闭输入流
FileWriter 是OutputStreamWriter的子类型,实际使用的类 write()函数,从内存往硬盘写入下一个字节 close()关闭输出流
用法和FileInputStream/FileOutputStream差不多,不过是以一个字符为单位进行的读写,而不是以一个字节为单位进行读写。
只能用于文本文件,绝对不能针对图片或其他文件进行读写。
package ioNio.io;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderAndWrite {
public static void main(String[] args) throws IOException {
FileReaderAndWrite fileReaderAndWrite = new FileReaderAndWrite();
fileReaderAndWrite.readFile();
fileReaderAndWrite.writeFile();
}
private void readFile() throws IOException {
FileReader fileReader = new FileReader("F:\\Codes\\LeetCode\\src\\tempfile\\readFile.txt");
int count;
char[] buf = new char[1024];
while ((count = fileReader.read(buf)) != -1) {
System.out.print(new String(buf, 0, count));
}
fileReader.close();
}
private void writeFile() throws IOException {
FileWriter fileWriter = new FileWriter("F:\\Codes\\LeetCode\\src\\tempfile\\writeFile.txt", true);
String string = "写入" + File.separator + "123";
fileWriter.write(string);
fileWriter.close();
}
}
字符缓冲流(是字符流的升级版,可以将数据部分放到缓冲区提高效率):
BufferedReader 是Reader的子类型,实际使用的类 read()函数,表示读取下一个字节 close()关闭输入流
BufferedWriter 是Writer的子类型,实际使用的类 write()函数,从内存往硬盘写入下一个字节 close()关闭输出流
用法和BufferedInputStream/BufferedOutputStream差不多,不过是以一个字符为单位进行的读写,而不是以一个字节为单位进行读写。BufferedReader可以进行按行读取,推荐使用这种读取方式。
package ioNio.io;
import java.io.*;
public class BufferedReaderAndWriter {
public static void main(String[] args) throws IOException {
BufferedReaderAndWriter bufferedReaderAndWriter = new BufferedReaderAndWriter();
bufferedReaderAndWriter.bufferedReadWord();
bufferedReaderAndWriter.bufferedReadLine();
bufferedReaderAndWriter.bufferedWriteWorld();
}
private void bufferedReadWord() throws IOException {
FileReader fileReader = new FileReader("F:\\Codes\\LeetCode\\src\\tempfile\\readFile.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int count;
char[] chars = new char[1024];
while ((count = bufferedReader.read(chars)) != -1) {
System.out.print(new String(chars, 0, count));
}
bufferedReader.close();
}
/**
* BufferedRead 可以支持按照行读取
* 体现了缓冲区用法
*/
private void bufferedReadLine() throws IOException {
FileReader fileReader = new FileReader("F:\\Codes\\LeetCode\\src\\tempfile\\readFile.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.print(line);
}
bufferedReader.close();
}
private void bufferedWriteWorld() throws IOException {
FileWriter fileWriter = new FileWriter("F:\\Codes\\LeetCode\\src\\tempfile\\writeFile.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
for (int i = 0; i < 10; i++) {
bufferedWriter.write("好好学习");
bufferedWriter.newLine(); // 根据系统,写入一个换行符
}
bufferedWriter.flush();
bufferedWriter.close();
}
}
IO的转换流:
有两个特殊的类,可以完成字节流和字符流之间的转换:
InputStreamReader:将硬盘中的数据读入,根据规定的格式,如UTF-8,GBK等,将字节转换成字符
OutputStreamWriter:将内存中的数据结构,由指定的格式,写入成字符,存储到硬盘中
package ioNio.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class InputStreamReaderTest {
public static void main(String[] args) throws IOException {
InputStreamReaderTest inputStreamReader = new InputStreamReaderTest();
inputStreamReader.inputStreamReader();
inputStreamReader.outputStreamReader();
}
// 将字节流转换为字符流 并解析(可以选择)
private void inputStreamReader() throws IOException {
FileInputStream fileInputStream = new FileInputStream("F:\\Codes\\LeetCode\\src\\tempfile\\readFile.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
int data = 0;
while ((data = inputStreamReader.read()) != -1) {
System.out.print((char) data);
}
inputStreamReader.close();
}
private void outputStreamReader() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("F:\\Codes\\LeetCode\\src\\tempfile\\writeFile.txt",true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"UTF-8");
String string = "new File 张三";
outputStreamWriter.write(string);
outputStreamWriter.flush();
outputStreamWriter.close();
}
}
IO对文件进行操作File:
File类是针对文件和文件夹定制的类,其使用方式比较简单,查询一下JDK API即可。
常用的File指令
其中有一个特别的接口:FileFilter,它可以过滤
File中的常用方法如下:
package ioNio.io;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) {
}
// File的常用路径
public void separator(){
System.out.println("路径分割符:" + File.pathSeparator );
System.out.println("名称分隔符:" + File.separator);
}
// 创建一个File 删除一个file
private void createFile() throws IOException {
File file = new File("F:\\Codes\\LeetCode\\src\\tempfile\\createFile.txt");
if(!file.exists()){
boolean createResult = file.createNewFile();
}
if(file.exists()){ // 直接删除
boolean deleteResult = file.delete();
}
if(file.exists()){ // 先不删除,等java执行完成之后,虚拟机停止之前删除掉
file.deleteOnExit();
}
}
/**
* 获取单层文件夹路径下的所有文件,通过实现类FileFilter进行一次过滤
* 如果accept返回的是true,则将文件放入数组中,否则不会放入数组中
*
* 如果需要深层文件,则需要递归过滤
*/
private void filterFile(){
File file = new File("D:\\abc");
File[] files2 = file.listFiles(new FileFilter(){
@Override
public boolean accept(File pathname){
if(pathname.getName().endsWith(".jpg")){
return true;
}
return false;
}
});
for(File fileTemp : files2){
System.out.println(fileTemp.getName());
}
}
}
遍历所有文件夹
递归遍历文件夹
// 找到文件夹dir下的所有文件
private void findallfile(File dir) {
File[] files = dir.listFiles();
if (files != null && files.length > 0) {
for (File fileTemp : files) {
if (fileTemp.isDirectory()) {
findallfile(fileTemp); // 递归
} else {
System.out.println(fileTemp.getAbsolutePath());
}
}
}
}
删除文件夹下的所有文件
// 递归删除dir路径下的所有文件
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());
}
}
}
}