Java学习笔记(十五):IO流

简介: Java学习笔记(十五):IO流

@[toc]
  
  
  

  

Java IO流原理

  

  

I/O 是 Input/Output 的缩写,I/O技术非常实用,用于处理设备之间的数据传输。如:读/写文件,网络通讯等。

Java程序中,对于数据的输入/输出操作以 的方式进行。

java.io包下提供了各种 “流” 类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

  

输入input :读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

输出output :将程序(内存)中数据输出到磁盘、光盘等存储设备中,能实现永久存储。

  
  
  

  

流的分类

  

  

按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)

按数据流的流向不同分为:输入流输出流

按流的角色不同分为:节点流处理流

  

抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

Java的IO流共涉及40多个类,看着多但实际上非常规则,都是从上面4个抽象基类派生出来的。

由这4个类派生出来的子类名称都是以其父类名作为子类名后缀。

  

如何选择:

对于 文本文件(.txt,.java,.c,.cpp),使用 字符流处理
对于 非文本文件(.jpg,.mp3,.avi,.doc,.ppt,...),使用 字节流处理

  
  
  

  

IO流体系

  

  

只写常用的几个
  

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
文件流 (节点流) FileInputStream FileOutputStream FileReader FileWriter
缓冲流 (处理流) BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 (处理流) InputStreamReader OutputStreamWriter

  

处理流是包裹在节点流外层的一种流,作用于已有流的基础之上。

  
  
  

  

节点流

  

  


先明确IO流的操作步骤,这就是模板,下面所有都是这样写的:

  1. 实例化File类的对象,指明要操作的文件
  2. 提供具体的流
  3. 数据的具体操作(读或写)
  4. 流的关闭

  

  

FileReader

  

分布来看:

// 1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");
// 2.FileReader流的实例化
FileReader fr = new FileReader(file);
// 3.数据的读入
// read(char[] cbuf):返回每次读入cbuf数组中的字符个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){

    // 方式一:循环遍历每次读到的cbuf
//    for (int i = 0; i < len; i++) {
//        System.out.print(cbuf[i]);
//    }

    // 方式二:把每次读到的cbuf变成字符串输出
    String str = new String(cbuf,0,len);
    System.out.print(str);
}
// 4.资源关闭
fr.close();

  

但此时并不完整,有编译时异常需要异常处理,加上 try-catch-finally,完整代码:

package IO.FileReaderWriterTest;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest2 {
    public static void main(String[] args) {
    
        FileReader fr = null;

        try {
        
            // 1.File类的实例化,指明要操作的文件
            File file = new File("hello.txt");

            // 2.FileReader流的实例化
            fr = new FileReader(file);

            // 3.数据的读入
            // read(char[] cbuf):返回每次读入cbuf数组中的字符个数。如果达到文件末尾,返回-1
            char[] cbuf = new char[5];
            int len;
            while((len = fr.read(cbuf)) != -1){

                // 方式一:循环遍历每次读到的cbuf
    //            for (int i = 0; i < len; i++) {
    //                System.out.print(cbuf[i]);
    //            }

                // 方式二:把每次读到的cbuf变成字符串输出
                String str = new String(cbuf,0,len);
                System.out.print(str);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 4.资源关闭
                assert fr != null;
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  

补充一点:
try-catch-finally 快捷键:Ctrl+Alt+T

在这里插入图片描述

Ctrl+Alt+T 不仅仅能用于生成 try-catch-finally 结构,还能一键生成各种结构体,非常好用!

  

  

FileWriter

  

// 1.实例化File类的对象,指明写到的文件
File file = new File("hello1.txt");
// 2.提供FileWriter流的对象
FileWriter fw = new FileWriter(file);

注意:
这里的 FileWriter构造器 new FileWriter(file,append) 可以选参数

  1. 不写默认为false或写上false:意思是在原文件上直接覆盖新的数据。
  2. 写true:在文件后加新的数据,就不覆盖原有的了。
// 3.数据写入
fw.write("我有一个梦想\n");
fw.write("你也得有一个梦想\n");
// 4.资源关闭
fw.close();

  
最后别忘了 try-catch-finally!

  

完整代码:

package IO.FileReaderWriterTest;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter fw = null;  // 追加模式写入

        try {
        
            // 1.实例化File类的对象,指明写到的文件
            File file = new File("hello1.txt");

            // 2.提供FileWriter流的对象
//        FileWriter fw = new FileWriter(file);   // append默认为false,直接覆盖
            fw = new FileWriter(file,true);

            // 3.数据写入
            fw.write("我有一个梦想\n");
            fw.write("你也得有一个梦想\n");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 4.资源关闭
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  

最后补充一点 read() 及其重载方法的使用:

在这里插入图片描述
读取单个字符。

返回值:读取的字符,如果已到达流的结尾,则为-1

抛出:IOException–如果发生I/O错误

  

在这里插入图片描述
将字符读入数组。此方法将一直阻塞,直到有一些输入可用、发生I/O错误或到达流的结尾。

参数:cbuf–目标缓冲区

返回值:读取的字符数,如果已到达流的结尾,则为-1

抛出:IOException–如果发生I/O错误

  

  

FileReader和FileWriter一起使用实现文件的复制

  

package IO.FileReaderWriterTest;

import java.io.*;

public class TestAll {
    public static void main(String[] args) {

        FileReader fr = null;
        FileWriter fw = null;
        try {
        
            // 1.造文件
            File file1 = new File("hello.txt");
            File file2 = new File("hello2.txt");

            // 2.造流
            fr = new FileReader(file1);
            fw = new FileWriter(file2,true);

            // 3.数据操作
            char[] cbuf = new char[5];
            int len;
            while((len = fr.read(cbuf)) != -1){
                // 方法一:
                for (int i = 0; i < len; i++) {
                    fw.write(cbuf[i]);
                }

                //方法二:  每次写出0到len的字符
//                fw.write(cbuf,0,len);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 4.关闭流
                assert fr != null;
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  

  

  

注意⭐细节:

在第3步数据操作时,字符流和字节流有所区别:
  

  1. 字符流:用 char[](char型数组)

  

  1. 字节流:用 byte[](byte型数组)

  

  

  

FileInputStream和FileOutputStream一起使用实现图片的复制

  

由于字节流和字符流使用方式几乎一模一样,所以直接写个总的了

package IO.FileInputOutputStreamTest;

import java.io.*;

public class TestAll {
    public static void main(String[] args) {

        FileInputStream fws = null;
        FileOutputStream fos = null;
        try {
            File file1 = new File("a3141ac538443882b3aca9f5e462b31.jpg");
            File file2 = new File("picture.jpg");

            fws = new FileInputStream(file1);
            fos = new FileOutputStream(file2);

            byte[] b = new byte[10];
            int len;
            while((len = fws.read(b)) != -1){
                fos.write(b,0,len);
            }
            System.out.println("复制成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fws != null;
                fws.close();
                assert fos != null;
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  
  
  

  

处理流

  

就是“套接”在已有流的基础上,进一步加工,实现更多功能。

  

  

  

缓冲流

  

缓冲流是处理流,是包裹在节点流上的流。
  

具体做法:

造流的时候多加一步。造完节点流后,造缓冲流即可。

之后就是按部就班的操作数据和关闭资源。

  

用的类有:

  • BufferedInputStream:字节缓冲输入流

  

  • BufferedOutputStream:字节缓冲输出流

  

  • BufferedReader:字符缓冲输入流

  

  • BufferedWriter:字符缓冲输出流

  

作用: 提高流的读取、写入速度。

能提高读写速度的原因: 内部提供了一个缓冲区。

  

  

缓冲流(字节型)实现非文本文件的复制(具体步骤)

  
1、造文件

File srcFile = new File("D:\\Java\\StudyPlus\\test.txt");
File destFile = new File("D:\\Java\\StudyPlus\\test2.txt");

  
2、造流 —— 先造里层的流,后造外层的流。就像穿衣服:先穿里层,后穿外层。

2.1、造节点流

FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);

2.2、造缓冲流

BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);

  
3、数据操作:读取,写入

byte[] b = new byte[10];
int len;
while((len = bis.read(b)) != -1){
    bos.write(b,0,len);
}

  
4、关资源

要求:先关闭外层的流,再关闭内层的流。即,先关外面后关里面。就像脱衣服:先脱外层,后脱里层。

偷懒: 关闭外层流的同时,内层流也会自动关闭。所以我们只需关外层即可,内层流的关闭可以省略。

bis.close();
bos.close();

  

总的代码:

package IO.Buffered;

import java.io.*;

public class BufferedInputOutputStream {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            // 1.造文件
            File srcFile = new File("D:\\Java\\StudyPlus\\a3141ac538443882b3aca9f5e462b31.jpg");
            File destFile = new File("D:\\Java\\StudyPlus\\picture1.jpg");

            // 2.造流     先造里层的流,后造外层的流。   穿衣服先穿里层,后穿外层。
            // 2.1造节点流
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            // 2.2造缓冲流(处理流)
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            // 3.复制的细节:读取、写入
            byte[] b = new byte[10];
            int len;
            while((len = bis.read(b)) != -1){
                bos.write(b,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 4.关资源
                // 要求:先关闭外层的流,再关闭内层的流。  先关外面后关里面。   脱衣服先脱外层,后脱里层。
                assert bis != null;
                bis.close();
                assert bos != null;
                bos.close();
                // 说明:关闭外层流的同时,内层流也会自动关闭。所以我们只需关外层即可,内层流的关闭可以省略。
                // fis.close();
                // fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  

  

缓冲流(字符型)实现文本文件的复制

  

package IO.Buffered;


import java.io.*;

public class BufferedReaderWriter {
    public static void main(String[] args) {

        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            File srcFile = new File("D:\\Java\\StudyPlus\\test.txt");
            File destFile = new File("D:\\Java\\StudyPlus\\test2.txt");

            FileReader fr = new FileReader(srcFile);
            FileWriter fw = new FileWriter(destFile);

            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);

            // 方法一:使用char型数组
//            char[] cbuf = new char[1024];
//            int len;
//            while((len = br.read(cbuf)) != -1){
//                bw.write(cbuf,0,len);
//            }

            // 方法二:使用String
            String data;
            while((data = br.readLine()) != null){
                // 换行的方式一: 手动添加 \n 换行
//                bw.write(data + "\n");  // data中不包含换行符
                // 换行的方式二: 调用方法
                bw.write(data);
                bw.newLine();   // 提供换行的操作
            }            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert br != null;
                br.close();
                assert bw != null;
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  

  

  

转换流

  

在这里插入图片描述
  

转换流: 属于字符流

  • InputStreamReader :将一个字节的输入流转换为字符的输入流
  • OutputStreamWriter :将一个字符的输出流转换为字节的输出流

  

作用: 提供字节流与字符流之间的转换

应用: 能改变文件的编码方式。如:utf-8 与 gbk间的相互转换

  

解码:字节、字节数组 ——→ 字符串、字符数组
编码:字符串、字符数组 ——→ 字节、字节数组

  
  
好记的口诀:
  
1、转化顺序和方向:

  • 先是 InputStreamReader :从左到右看 InputStream ——→ Reader 字节转字符
  • 然后 OutputStreamWriter :从右到左看 Writer ——→ OutputStream 字符转字节

2、用的流:

  • InputStreamReaderFileInputStream
  • OutputStreamWriterFileOutputStream

  
  

注意:

因为要实现编码格式的转换,所以在 new转换流时,在构造器里写转换前后的参数。

InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");

转换前是 utf-8,转换后为 gbk

还有一点:

InputStreamReader 构造器中默认编码方式为 utf-8

  

  

转换流实现文件的读入和写出

  

package IO.转换流;

import java.io.*;
import java.nio.charset.StandardCharsets;

public class Test {
    public static void main(String[] args) {

        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            FileInputStream fis = new FileInputStream("test.txt");
            FileOutputStream fos = new FileOutputStream("test_gbk.txt");

            isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
            osw = new OutputStreamWriter(fos,"gbk");

            char[] cbuf = new char[20];
            int len;
            while((len = isr.read(cbuf)) != -1){
                osw.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert isr != null;
                isr.close();
                assert osw != null;
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

此时,新文件的编码方式就变了,变成 gbk了。

相关文章
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
73 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
从Java环境的搭建到实际代码的编写,从基本用法的讲解到底层原理的剖析,深度解析Java基础知识。本文是《Java学习路线》专栏的起始文章,旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时间内成长为高级开发。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
|
1月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
36 1
|
1月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
85 1
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
1月前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
48 0
|
2月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
1月前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
36 0
|
1月前
|
Java 程序员 开发工具
java学习笔记
java学习笔记
38 0
下一篇
无影云桌面