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流详解(二)
Java零基础入门之IO流详解(二)
|
1天前
|
存储 缓存 Java
Java零基础入门之IO流详解(一)
Java零基础入门之IO流详解(一)
|
2天前
|
设计模式 安全 Oracle
Java学习笔记:从入门到精通
Java学习笔记:从入门到精通
|
4天前
|
机器学习/深度学习 Java 关系型数据库
程序员必知:关于高淇JAVA中SORM总结学习笔记详细个人解释
程序员必知:关于高淇JAVA中SORM总结学习笔记详细个人解释
|
5天前
|
机器学习/深度学习 Java 关系型数据库
程序员必知:关于高淇JAVA中SORM总结学习笔记详细个人解释
程序员必知:关于高淇JAVA中SORM总结学习笔记详细个人解释
|
5天前
|
存储 Java
杭州 java IO流详解(借鉴-侵-删)
杭州 java IO流详解(借鉴-侵-删)
8 0
|
6天前
|
Java 数据处理 开发者
Java IO流专家级教程:深入理解InputStream/OutputStream和Reader/Writer的内部机制
【6月更文挑战第26天】Java IO流涉及字节流(InputStream/OutputStream)和字符流(Reader/Writer),用于高效处理数据输入输出。InputStream/OutputStream处理二进制数据,常使用缓冲提升性能;Reader/Writer处理文本,关注字符编码转换。两者都有阻塞IO操作,但Java NIO支持非阻塞。示例代码展示了如何使用FileInputStream/FileOutputStream和FileReader/FileWriter读写文件。理解这些流的内部机制有助于优化代码性能。
|
6天前
|
存储 自然语言处理 Java
Java IO流完全手册:字节流和字符流的常见应用场景分析!
【6月更文挑战第26天】Java IO流涵盖字节流和字符流,字节流用于二进制文件读写及网络通信,如图片和音频处理;字符流适用于文本文件操作,支持多语言编码,确保文本正确性。在处理数据时,根据内容类型选择合适的流至关重要。
|
6天前
|
Java 开发者
Java IO流实战技巧:如何优化InputStream/OutputStream和Reader/Writer的使用?
【6月更文挑战第26天】Java IO流优化涉及缓冲、资源管理、字符编码和流式处理。使用Buffered流提高读写效率,如`BufferedInputStream`和`BufferedReader`。确保资源关闭使用try-with-resources,如`try (InputStream is = ...) {...}`。处理文本时指定编码,如`InputStreamReader(is, StandardCharsets.UTF_8)`防止乱码。流式处理大文件,分块读写避免内存溢出,以减少内存占用。这些技巧能提升程序性能和健壮性。
|
6天前
|
自然语言处理 Java
Java IO流进阶教程:掌握字节流和字符流的高级用法!
【6月更文挑战第26天】Java IO流助你高效交换数据,包括字节流(InputStream/OutputStream)和字符流(Reader/Writer)的高级技巧。缓冲流(Buffered*)提升读写性能,对象流(Object*Stream)支持对象序列化。字符流的BufferedReader/BufferedWriter优化文本处理,注意字符集如UTF-8用于编码转换。掌握这些,优化IO操作,提升代码质量。

热门文章

最新文章