• 【Java-----IO流(一)之字节流详解】


    IO流概述和分类

    IO流概述

    • IO:输入/输出(Input/Output)
    • 流:是一种抽象概念,对数据传输的总称,也就是说数据在设备间的传输成为流,流的本质是数据传输
    • IO流:用来处理设备间数据传输问题的,常见的应用如:文件复制,文件上传,文件下载

    IO流分类

    按照数据的流向(以内存作为参照物)

    • 输入流:往内存中去,叫做输入(Input),或者叫做读(Read)
    • 输出流:从内存中出来,叫做输出(Output),或者叫做写(Write)

    按照数据类型来分

    • 字节流:字节输入流,字节输出流
    • 字符流:字符输入流,字符输出流

    一般来说,IO流的分类是按照数据类型来分的

    字节流概述

    字节流是按照字节的方式读取数据,一次读取一个字节,也就是8个二进制位,这种流是万能的,什么类型的文件都可以读取,包括:文本文件,图片,声音文件,视频文件等。通常如果文件能通过记事本打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流。如果不知道该使用哪种类型的流,就使用字节流。

    字节流抽象基类

    • InputStream:这个抽象类是表示字节输入流的所有类的超类
    • OutputStream:这个抽象类是表示字节输出流的所有类的超类
    • 子类名特点:子类名称都是以其父类名作为子类名的后缀

    字节输出流写数据

    OutputStream抽象类功能是将指定的字节信息写出到目的地,它定义了字节输出流的基本共性功能方法。

    • public void close():关闭此输出流并释放与此流相关联的任何系统资源
    • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出
    • public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流
    • public void write(byte[] b,int off,int len):从指定的字节数组写入len字节,从偏移量off开始写入到此输出流
    • public abstract void write(int b):将指定的字节写入此输出流

    注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源

    FileOutputStream类

    OutputStream有很多子类,以最简单常用的FileOutputStream为例:FileOutputStream类是文件输出流,用于将数据写出到文件

    构造方法

    public FileOutputStream(File file):创建文件输出流以写入由指定的file对象表示的文件

    1. File file=new File("D:\\aaa\\helloworld.txt");
    2. FileOutputStream fos=new FileOutputStream(file);

    public FileOutputStream(String name):创建文件输出流以写入指定名称的文件

    FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");

    当你创建一个流对象时,必须传入一个文件路径,该路径下如果没有这个文件,会创建该文件,如果有这个文件,会清空这个文件的数据。

    写出字节数据到文件

    使用字节输出流写数据的步骤:

    1. 创建字节输出流对象(调用系统功能创建文件,创建字节输出流对象,让字节输出流对象指向创建好的文件)
    2. 调用字节输出流对象的写数据方法
    3. 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

    1  write(int b):写出字节方法,每次可以写出一个字节数据

    1. File file=new File("D:\\aaa\\helloworld.txt");
    2. FileOutputStream fos=new FileOutputStream(file);
    3. fos.write(65);
    4. fos.write(66);
    5. fos.write(67);
    6. fos.close();
    7. //文件中写入:ABC

    2  write(byte[] b):写出字节数组,每次可以写出数组中的数据

    1. byte[] b="abcde".getBytes();
    2. FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. fos.write(b);
    4. fos.close();
    5. //文件中写入:abcde

    3  write(byte[] b,int off,int len):写出指定长度字节数组,每次写出从off索引开始,len个字节

    1. byte[] b="12345".getBytes();
    2. FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. fos.write(b,1,3);
    4. fos.close();
    5. //文件中写入:234

    数据追加续写

    上面的构造方法,每次程序运行创建输出流对象,都会清空目标文件中的数据,如何保留目标文件中的数据,还能继续添加新数据呢?看下面两个构造方法:

    public FileOutputStream(File file,boolean append):创建文件输出流以写入由指定的file对象表示的文件

    public FileOutputStream(String name,boolean append):创建文件输出流以写入指定名称的文件

    这两个构造方法,参数中都需要传入一个boolean类型的值,true表示追加数据,false表示清空原有数据,这样创建的输出流对象,就可以指定是否追加续写了。示例代码如下:

    1. byte[] b="12345".getBytes();
    2. FileOutputStream fos1=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. fos1.write(b,1,3);
    4. fos1.close();
    5. FileOutputStream fos2=new FileOutputStream("D:\\aaa\\helloworld.txt",true);
    6. fos2.write(97);
    7. fos2.write(98);
    8. fos2.write(99);
    9. fos2.close();
    10. //文件中内容为:234abc

    写出换行

    回车符\r和换行符\n

    • 回车符:回到一行的开头(return)
    • 换行符:下一行(nextline)

    系统中的换行

    • windows系统里:每行结尾是回车+换行,即\r\n
    • unix系统里:每行结尾只有换行,即\n
    • mac系统里:每行结尾是回车,即\r。从mac OS X开始与linux统一

    写出换行,示例代码如下:

    1. byte[] b="12345".getBytes();
    2. FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. for(int i=0;i
    4. fos.write(b[i]);
    5. fos.write("\r\n".getBytes());
    6. }
    7. fos.close();
    8. /*文件中写入:1
    9. 2
    10. 3
    11. 4
    12. 5
    13. */

    字节输入流读数据

    InputStream抽象类可以读取字节信息到内存中,它定义了字节输入流的基本共性功能方法。

    • public void close():关闭此输入流并释放与此流相关联的任何系统资源
    • public abstract int read():从输入流读取数据的下一个字节
    • public int read(byte[] b):从输入流中读取一些字节数,并将它们存储到字节数组b中

    注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源

    FileInputStream类

    InputStream有很多子类,以最简单常用的FileInputStream为例:FileInputStream类是文件输入流,从文件中读取字节

    FileInputStream(File file):通过打开与实际文件的连接来创建一个FileInputStream对象,该文件由文件系统中的File对象指定

    1. File file=new File("D:\\aaa\\helloworld.txt");
    2. FileInputStream fis=new FileInputStream(file);

    FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream对象,该文件由文件系统中的路径名name指定

    FileInputStream fis=new FileInputStream("D:\\aaa\\helloworld.txt");

    当你创建一个流对象时,必须传入一个文件路径,该路径下,如果没有该文件,会抛出FileNotFoundException

    从文件中读取字节数据

    使用字节输入流读取数据的步骤:

    1. 创建字节输入流对象
    2. 调用字节输入流对象的读数据方法
    3. 释放资源

    1  int read():读取字节,每次可以读取一个字节的数据,读取到文件末尾,返回-1

    1. File file=new File("D:\\aaa\\helloworld.txt");
    2. FileOutputStream fos=new FileOutputStream(file);
    3. fos.write(65);
    4. fos.write(66);
    5. fos.write(67);
    6. fos.close();
    7. FileInputStream fis=new FileInputStream("D:\\aaa\\helloworld.txt");
    8. int r;
    9. while((r=fis.read())!=-1) {
    10. System.out.println((char)r);
    11. }
    12. fis.close();
    13. /*输出:A
    14. B
    15. C
    16. */

    注意:

    • 虽然读取了一个字节,但是会自动提升为int类型
    • 流操作完毕后,必须调用close方法,释放系统资源

    2  int read(byte[] b):使用字节数组读取,每次读取b.length个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1

    1. byte[] b="abcde".getBytes();
    2. FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. fos.write(b);
    4. fos.close();
    5. FileInputStream fis=new FileInputStream("D:\\aaa\\helloworld.txt");
    6. int len;
    7. byte[] bb=new byte[2];
    8. while((len=fis.read(bb))!=-1) {
    9. System.out.println(new String(bb));
    10. }
    11. fis.close();
    12. /*输出:ab
    13. cd
    14. ed
    15. */

    最后一次输出了ed是由于最后一次读取时,只读取一个字节e,数组中上次读取的数据没有被完全替换,所以要通过len获取有效的字节,改进代码如下:

    1. byte[] b="abcde".getBytes();
    2. FileOutputStream fos=new FileOutputStream("D:\\aaa\\helloworld.txt");
    3. fos.write(b);
    4. fos.close();
    5. FileInputStream fis=new FileInputStream("D:\\aaa\\helloworld.txt");
    6. int len;
    7. byte[] bb=new byte[2];
    8. while((len=fis.read(bb))!=-1) {
    9. System.out.println(new String(bb,0,len));
    10. }
    11. fis.close();
    12. /*输出:ab
    13. cd
    14. e
    15. */

    使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,建议开发中使用。

  • 相关阅读:
    Ribbon负载均衡的原理以及负载均衡的配置和饥饿加载
    MySQL应用——常见故障分析和检查
    2021最新中高级Java面试题目,Java面试题汇总
    10、MyBatis的缓存
    从零开始,开发一个 Web Office 套件(15):拖动边框,平移编辑器
    读未提交-为什么可以读到别人修改的数据
    windows部署python项目(以Flask为例)到docker,通过脚本一键生成dockerfile并构建镜像启动容器
    ‘setuptools‘ is a dependency of conda and cannot be removed from
    使用 .net + blazor 做一个 kubernetes 开源文件系统
    《统计学习方法》第八章 提升方法(原理+代码)
  • 原文地址:https://blog.csdn.net/qq_45071131/article/details/127554736