java IO流,NIO流文件读取写入

发布于:2024-04-27 ⋅ 阅读:(30) ⋅ 点赞:(0)

目录

IO输入流(读取磁盘文件至内存中)

IO输出流(读取内存中的数据写入到磁盘)

IO流读取文件并写入另一个文件(拷贝)

用字节输入输出流实现

 用字符输入输出流实现 

NIO流读取文件写入 

输入输出管道流(Channel)形式

ByteBuffer字节缓冲区形式 


IO输入流(读取磁盘文件至内存中)

大致分为:字节输入流(以字节方式读取),字符输入流(以字符或一行字符读取),对象输入流(读取为一个对象,应该是吧.....)

常用输入流如下:

// 文件字节输入流
FileInputStream fileInputStream = new FileInputStream("文件路径 或 File对象");
// 字节输入缓冲流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
// 文件字符输入流
FileReader fileReader = new FileReader("文件路径 或 File对象");
// 字符输入转换流,以指定编码读取文件,第二个参数是格式编码,可以输入字符串,如:"UTF-8","GBK"
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
// 字符输入缓冲流
BufferedReader bufferedReader = new BufferedReader(fileReader 或 inputStreamReader);

输入流和输入缓冲流区别:简单点说缓冲流读取更快,因为它内部有8k缓存空间。


IO输出流(读取内存中的数据写入到磁盘)

大致分为:字节输出流(以字节方式输出),字符输出流(以字符或一行字符输出),对象输出流(输出一个对象到文件中)

常用输入流如下:

// 字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("文件路径 或 File对象");
// 字节输出缓冲流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
// 字符输出流
FileWriter fileWriter = new FileWriter("文件路径 或 File对象");
// 字符输出转换流,以指定编码写入文件,第二个参数是格式编码,可以输入字符串,如:"UTF-8","GBK"
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
// 字符输出缓冲流
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter 或 outputStreamWriter);

输出流和输出缓冲流区别:简单点说缓冲流写入更快,小文件体现不出来,上G的文件就能体现出来了。 

注意:构建输出流时,如果输出文件里面原本有内容,则会被直接清空。


IO流读取文件并写入另一个文件(拷贝)


拷贝D盘的old.txt文件,生成一个新的new.txt文件


用字节输入输出流实现


    public static void main(String[] args) {
        // 原文件(输入文件)
        File inputFile = new File("D:/AAA/old.txt");
        // 新文件输出路径
        File outputParentFile = new File("D:/AAA");
        // 新文件(输出文件)
        File outputFile = null;
        if (!inputFile.exists()) {
            String errorMsg = new StringBuffer("原文件不存在:")
                    .append(inputFile.getAbsolutePath())
                    .toString();
            logger.warn(errorMsg);
            throw new RuntimeException(errorMsg);
        }
        // 输出路径不存在,且创建路径失败
        if (!outputParentFile.exists() && !outputParentFile.mkdirs()) {
            String errorMsg = new StringBuffer("创建文件输出路径失败:")
                    .append(outputParentFile.getAbsolutePath())
                    .toString();
            logger.warn(errorMsg);
            throw new RuntimeException(errorMsg);
        }
        // 创建输出文件对象
        outputFile = new File(outputParentFile, "new.txt");
        if (!outputFile.exists()) {
            try {
                outputFile.createNewFile();
            } catch (IOException e) {
                logger.warn("创建输出文件失败", e);
                throw new RuntimeException("创建输出文件失败");
            }
        }
        try (
                // 创建字节输入流
                FileInputStream fileInputStream = new FileInputStream(inputFile);
                // 创建字节输入缓冲流
                BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
                // 创建字节输出流
                FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
                // 创建字节输出缓冲流
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                ){
            // 一次读取1024个字节,可以自己决定大小
            byte[] bytes = new byte[1024];
            while(bufferedInputStream.read(bytes) != -1) {
                // 写入
                bufferedOutputStream.write(bytes);
            }
            System.out.println("复制成功!");
            // 后面不用写关闭输入输出流的代码,写在try()里面,编译时会自动生成关闭资源代码
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

上面用到的类都是 java.io包下的,字节方式输入输出可以用于其他类型文件,比如图片视频等。

运行结果:


 用字符输入输出流实现 


public static void main(String[] args) {
    // 原文件(输入文件)
    File inputFile = new File("D:/AAA/old.txt");
    // 新文件输出路径
    File outputParentFile = new File("D:/AAA");
    // 新文件(输出文件)
    File outputFile = null;
    if (!inputFile.exists()) {
        String errorMsg = new StringBuffer("原文件不存在:")
                .append(inputFile.getAbsolutePath())
                .toString();
        logger.warn(errorMsg);
        throw new RuntimeException(errorMsg);
    }
    // 输出路径不存在,且创建路径失败
    if (!outputParentFile.exists() && !outputParentFile.mkdirs()) {
        String errorMsg = new StringBuffer("创建文件输出路径失败:")
                .append(outputParentFile.getAbsolutePath())
                .toString();
        logger.warn(errorMsg);
        throw new RuntimeException(errorMsg);
    }
    // 创建输出文件对象
    outputFile = new File(outputParentFile, "new.txt");
    if (!outputFile.exists()) {
        try {
            outputFile.createNewFile();
        } catch (IOException e) {
            logger.warn("创建输出文件失败", e);
            throw new RuntimeException("创建输出文件失败");
        }
    }
    try (
            // 创建字符输入流
            FileReader fileReader = new FileReader(inputFile);
            // 创建字符输入缓冲流
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            // 创建字符输出流
            FileWriter fileWriter = new FileWriter(outputFile);
            // 创建字节输出缓冲流
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
            ){
        // 当前行
        String currentLine = null;
        // StringUtils.isNotBlank 判断是否不为空
        // bufferedReader.readLine() 一次读取一行文本
        while(StringUtils.isNotBlank((currentLine = bufferedReader.readLine()))) {
            // 写入当前行文本
            bufferedWriter.write(currentLine);
            // 新建一行
            bufferedWriter.newLine();
        }
        // 还要写入其他内容可以继续 bufferedWriter.write("其他内容");
        System.out.println("复制成功!");
        // 后面不用写关闭输入输出流的代码,写在try()里面,编译时会自动生成关闭资源代码
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

NIO流读取文件写入 


输入输出管道流(Channel)形式


正式使用的时候,记得加代码判断输入文件是否存在,输出文件目录是否存在,如果其中一个不存在会报错的,这里就不写了,代码参照上面IO流的。 

    public static void main(String[] args) {
        try(
                FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
                FileChannel inputChannel = fileInputStream.getChannel();
                FileOutputStream fileOutputStream = new FileOutputStream("D:/A_COPY.txt");
                FileChannel outputChannel = fileOutputStream.getChannel();
                ) {
            long currentRead = 0;
            // 理论上通过管道流的transferTo方法一次就可以交互输出完成,不需要while,但大文件可能会受限于操作系统,一次性没法输出完成,所以加一个while保险一点
            while((currentRead += inputChannel.transferTo(currentRead, inputChannel.size(), outputChannel)) < inputChannel.size());
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

ByteBuffer字节缓冲区形式 


 正式使用的时候,记得加代码判断输入文件是否存在,输出文件目录是否存在,如果其中一个不存在会报错的,这里就不写了,代码参照上面IO流的。 

public static void main(String[] args) {
        try(
                FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
                FileChannel inputChannel = fileInputStream.getChannel();
                FileOutputStream fileOutputStream = new FileOutputStream("D:/A_COPY.txt");
                FileChannel outputChannel = fileOutputStream.getChannel();
                ) {
            // 通过ByteBuffer.allocate创建出一个指定容量的ByteBuffer,一旦指定容量就不能改变其大小。
            // 当前指定一次读取写入20M,推荐不低于10M,一次性操作的字节越多,大文件读取写入就越快,当然性能消耗更大。
            // 构造ByteBuffer有两个方法,ByteBuffer.allocate和ByteBuffer.allocateDirect,两个方法都是相同入参,含义却不同。
            // ByteBuffer.allocate(capacity)分配的是非直接缓冲区,非直接缓冲区的操作会在Java堆内存中进行,数据的读写会通过Java堆来传递。、
            // ByteBuffer.allocateDirect(capacity)分配的是直接缓冲区, 直接缓冲区的操作可以通过本地I/O传递,避免了在Java堆和本地堆之间的数据传输,可能在某些情况下提供更好的性能。
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024 * 10 * 10);
            int currentReadSize;
            while((currentReadSize = inputChannel.read(byteBuffer)) > -1) {
                // 将byteBuffer翻转,写模式和读模式转换
                byteBuffer.flip();
                outputChannel.write(byteBuffer);
                // 清空byteBuffer,但只是下标重置,实际上内存并没有释放
                byteBuffer.clear();
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

 大文件推荐用NIO流操作,读取写入更快,几KB小文件都可以吧。至于IO流和NIO流区别,自己百度吧。


最后再说一个ByteArrayInputStream,ByteArrayOutputStream,有时候我们想读取一个文件的全部字节成一个byte[],然后再进行操作,比如转换成字符串啥的,但按照上面写出的方法,似乎都不满足, 这时候用ByteArray????Stream可以做到。


    public static void main(String[] args) {
        try(
                FileInputStream fileInputStream = new FileInputStream("D:/A.txt");
                BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                ) {
            byte[] bytes = new byte[1024];
            int currentReadSize;
            while ((currentReadSize = bufferedInputStream.read(bytes)) != -1) {
                byteArrayOutputStream.write(bytes, 0, currentReadSize);
            }
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            System.out.println(new String(byteArray));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

码字不易,于你有利,勿忘点赞


网站公告

今日签到

点亮在社区的每一天
去签到