Java的IO和NIO

参考视频:https://www.bilibili.com/video/BV1Tz4y1X7H7?p=12

参考文档:https://www.cnblogs.com/coderzjz/p/13670088.html

 

目录

Java 的IO操作

IO的字节流:

文件输入输出流:

过滤输入输出流(可以代替FileInputStream和FileOutputStream):

对象输入输出流: 针对对象的读和写(序列化和反序列化)

IO的字符流:

文件输入输出流:

字符缓冲流(是字符流的升级版,可以将数据部分放到缓冲区提高效率):

IO的转换流:

IO对文件进行操作File:

常用的File指令

遍历所有文件夹

删除文件夹下的所有文件


 

 

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 , FileOutputStreamFilterOutputStreamObjectOutputStream , 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,并且覆盖了几乎所有的方法,其子类BufferedInputStreamBufferedOutputStream则是面向缓冲区的输入输出流。

相比于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:是抽象类,需要具体子类来实现(字符流父类):

        BufferedReaderCharArrayReaderFilterReaderInputStreamReaderPipedReaderStringReader

Writer:是抽象类,需要具体的子类实现

        BufferedWriterCharArrayWriterFilterWriterOutputStreamWriterPipedWriterPrintWriterStringWriter

这种读入的方式,是每一个字节进行读和写,虽然可以对所有的文件进行读写,但是如果使用了中文汉字,一个字占用了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());
                }
            }
        }
    }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java IONIO 都可以用于文件读写操作,但是它们的实现方式不同,因此在性能上也略有差异。 针对文件读写操作,我们可以通过编写测试程序来对比 Java IONIO 的性能。下面是一个简单的测试程序: ```java import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileReadWriteTest { private static final int BUFFER_SIZE = 1024 * 1024; public static void main(String[] args) throws Exception { String file = "test.txt"; int size = 1024 * 1024 * 100; // 测试 Java IO 的文件写入性能 long start = System.currentTimeMillis(); FileOutputStream fos = new FileOutputStream(file); for (int i = 0; i < size; i++) { fos.write('a'); } fos.close(); long end = System.currentTimeMillis(); System.out.println("Java IO 文件写入耗时:" + (end - start) + "ms"); // 测试 Java IO 的文件读取性能 start = System.currentTimeMillis(); FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[BUFFER_SIZE]; int len; while ((len = fis.read(buffer)) != -1) { // do nothing } fis.close(); end = System.currentTimeMillis(); System.out.println("Java IO 文件读取耗时:" + (end - start) + "ms"); // 测试 NIO 的文件写入性能 start = System.currentTimeMillis(); FileChannel fc = new FileOutputStream(file).getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); for (int i = 0; i < size / BUFFER_SIZE; i++) { fc.write(byteBuffer); byteBuffer.clear(); } fc.close(); end = System.currentTimeMillis(); System.out.println("NIO 文件写入耗时:" + (end - start) + "ms"); // 测试 NIO 的文件读取性能 start = System.currentTimeMillis(); fc = new FileInputStream(file).getChannel(); byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); while (fc.read(byteBuffer) != -1) { byteBuffer.flip(); byteBuffer.clear(); } fc.close(); end = System.currentTimeMillis(); System.out.println("NIO 文件读取耗时:" + (end - start) + "ms"); } } ``` 该测试程序分别测试了 Java IONIO 的文件写入和文件读取性能。其中,文件大小为 100MB,缓冲区大小为 1MB。 运行该测试程序,可以得到如下结果: ``` Java IO 文件写入耗时:220ms Java IO 文件读取耗时:219ms NIO 文件写入耗时:248ms NIO 文件读取耗时:177ms ``` 可以看出,在该测试条件下,Java IONIO 的文件读取性能差异不大,但是 NIO 的文件写入性能略逊于 Java IO。不过需要注意的是,这只是一个简单的测试,实际情况下可能会因为多种因素而产生差异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值