十一、Java 输入_输出(I_O流)

I/O 流是所有程序都必需的部分——使用输入机制,允许程序读取外部数据、用户输入数据;使用输出机制,允许程序记录运行状态,将程序数据输出到磁盘、光盘等存储设备中。
Java 的 IO 通过 java.io 包下的类和接口支持,主要包括输入、输出两种 IO 流,每种输入、输出又可分为字节流字符流两大类。通常字节流的功能比字符流的功能强大,因为计算机里所有的数据都是二进制,二字节流可处理所有二进制文件。但一般我们有这样一个规则:如果输入/输出的内容是文本内容,则应该使用字符流;如果进行输入/输出的内容是二进制内容,则应该使用字符流。

在这里插入图片描述


Java 输入/输出流体系中常用分类,下面会介绍其中的一些

理解 Java 的 IO 流

Java 的 IO 流是实现输入/输出的基础。下面从不同角度来对流进行分类。

输入流和输出流

按照流向来分:

  • 输入流:只能从中读取数据,而不能向其写入数据
  • 输出流:只能向其写入数据,而不能从中读取数据
  • **例如,数据从内存到硬盘,通常称为输出流,**这里的输入、输出都是从程序运行的内存的角度来划分的。

字节流和字符流

按照操作数据单元来分:

  • 字节流:操作的数据单元是 8 位的字节
  • 字符流:操作的数据单元是 16 位的字符
  • 字节流和字符流的用法几乎完全一样。

节点流和处理流

按照角色来分:

  • 节点流:可以从/向一个特定的 IO 设备读/写数据的流,也被称为低级流
  • 处理流:用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据读/写功能,也被称为高级流。

介绍完各个流的分类,下面会着重进行介绍他们的使用。

File 类

File 类可使用文件路径字符串来创建 File 实例。而 File 类提供了很多方法来操作文件和目录,在这里直接进行代码演示,来看一下比较常用的方法:

 public static void main(String[] args) throws IOException {
        {
            //以当前路径来创建一个File对象,括号里的是文件路径字符串,标识当前路径
            File file = new File(".");
            //直接获取文件名,输出一点
            System.out.println(file.getName());
            //获取相对路径的父路径可能出错,下面代码输出为null
            System.out.println(file.getParent());
            //获取绝对路径
            System.out.println(file.getAbsoluteFile());
            //获取上一级路径
            System.out.println(file.getAbsoluteFile().getParent());
            //在当前路径下创建一个临时文件
            File tempFile = File.createTempFile("aaa",".txt",file);
            //指定当JVM退出时删除该文件
            tempFile.deleteOnExit();
            //以系统当前时间作为新文件名来创建文件
            File newFile = new File(System.currentTimeMillis() + "");
            System.out.println("newFile是否存在:" + newFile.exists());
            //以指定newFile来创建一个目录,因为newFile已经存在
            //所以下面方法返回false,即无法创建该目录
            newFile.mkdir();
            //使用list()方法列出当前路径 下的所有文件和路径
            String[] fileList = file.list();
            System.out.println("=====当前路径下所有文件和路径如下======");
            for( String fileName : fileList){
                System.out.println(fileName);
            }
            //listRoots()静态方法列出所有的磁盘根路径
            File[] roots = File.listRoots();
            System.out.println("========系统所有根路径如下=========");
            for(File root : roots){
                System.out.println(root);
            }

        }

在这里,就不贴结构图咯,各位小伙伴可以直接试一下。

字节流和字符流

下面详细介绍字节流和字符流的具体使用:

InputStream 和 Reader

InputStream 和 Reader 是所有输入流的抽象基类,本身并不能创建实例执行输入,但它们将成为所有输入流的模板。
在 InputStream 里包含下面三个方法:

  • int Read():从输入流中读取单个字节,返回所读取的字节数据。
  • int read(byte[] b):从输入流中最多读取 b.length 个字节的数据,并将其存储在字节数组 b 中,返回实际读取的字节数。
  • int read(byte[] b,int off,int len):从输入流中最多读取 len 个字节的数据,并将其存储在数组 b 中;放入数组 b 中时,并不是从数组起点开始,而是从 off 位置开始,返回实际读取的字节数。

在 Read 里包含下面三个方法:

  • int Read():从输入流中读取单个字符,返回所读取的字符数据。
  • int read(char[] cbuf):从输入流中最多读取 cbuf.length 个字节的数据,并将其存储在字节数组 b 中,返回实际读取的字节数。
  • int read(byte[] cbuf,int off,int len):从输入流中最多读取 len 个字节的数据,并将其存储在数组 cbuf 中;放入数组 cbuf 中时,并不是从数组起点开始,而是从 off 位置开始,返回实际读取的字节数。

从上面的方法来看,字节流和字符流的方法几乎都是一样的。只不过是操作数据单元不同罢了。

OutputStream 和 Writer

OutputStream 和 Writer 也非常相似,两个流都提供了如下三个方法:

  • void write(int c):将指定的字节/字符输出到输出流中,其中 c 既可以代表字节,也可代表字符。
  • void write(byte[]/char[] buf):将指定的字节/字符数组的数据输出到指定输出流中。
  • void write(byte[]/char[] buf,int off,int len):将字节数组/字符数组中从 off 位置开始,长度为 len 的字节/字符输出到输出流中。
  • 因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来代替字符数组,即以 String 对象作为参数。Writer 里还包含如下两个方法:
    • void write(String str):将 str 字符串里包含的字符输出到指定输出流中。
    • void write(String str,int off,int len):将 str 字符串里从 off 位置开始,长度为 len 的字符输出到指定输出流中。

注意:使用 IO 流执行输出时,不要忘记关闭输出流。

处理流的用法

使用处理流时的思路是,使用处理流来包装节点流,程序通过处理流来执行输入/输出功能,让节点流与底层的 I/O设备、文件交互。
识别处理流非常简单:只要流的构造器参数不是一个物理节点,而是已经存在的流,那么这种流就一定是处理流;而所有节点流都是直接以物理 IO 节点作为构造器参数的。
处理流优势:

  • 对开发人员来说,使用处理流进行输入/输出操作更简单
  • 使用处理流的执行效率更高。
 public static void main(String[] args){

        try (
                FileOutputStream fos = new FileOutputStream("test.txt");
                PrintStream ps = new PrintStream(fos))
        {
            //使用PrintStream执行输出
            ps.println("普通字符串");
            //使用PrintStream输出对象
            ps.println(new PrintStreamTest());
        }
        catch (IOException ioe)
        {
            ioe.printStackTrace();
        }

    }

上面的代码,先定义了一个节点输出流 FileOutPutSteam ,然后程序使用 PrintStream 包装了该节点输出流,最后使用 PrintStream 输出字符串、输出对象。

在使用处理流包装了底层节点流之后,关闭流资源时,只要关闭最上层的处理流即可。关闭最上层的处理流时,系统会自动关闭被该处理流包装的节点流。

转换流

IO 流还提供了两个转换流,用于字节流转换成字符流,其中** InputStreamReader 将字节输入流转换成字符输入流,OutputStreamWriter 将字节输出流转换成字符输出流。**
那么问题来了,为什么没有把字符流转换成字节流的转换流呢?
因为,字节流使用范围广,但字符流比字节流操作方便,如果已经有一个操作方便了的字节流,为什么要转换成字节流呢?但如果有一个内容都是文本内容的字节流,那么现在可能就需要转换为字符流方便我们操作了。

  public static void main(String[] args){
        try(
                //将System.in 对象转换成Reader对象
                InputStreamReader reader = new InputStreamReader(System.in);
                //将普通的Reader包装成BufferedReader
                final BufferedReader br = new BufferedReader(reader))
        {
            String line = null;
            //循环逐行读取
            while((line = br.readLine()) != null){
                //如果读取的字符串“exit”,则程序退出
                if(line.equals("exit")){
                    System.exit(1);
                }
                System.out.println("输入内容为:" + line);
            }
        }
        catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }

上面的程序**将输入的字符转换成字节,**把 System.in 包装成具有缓冲功能的 BufferedReader ,它可以依次读取一行文本——以换行符为标志;如果没有换行符,则程序阻塞,直至读到换行符位置。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值