Java总结进阶之路 (基础四)I/O流



前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是IO流

IO流值得是 输入流(Input stream),输出流/(Ouput stream)的简称,是计算机程序用于处理输入和输出的一种抽象的概念

Input Stream 输入流

输入流的层次结构

  • InputStream(字节输入流):所有输入流的父类,提供了读取子节点的基本方法,Read(字符输入流):用于读取字符数据的抽象类 继承自InputStreamReader
    • FileInputStream:用于文件进行读取数据的输入流
    • ByteArrayInputStream:从字节数组中读取数据的输入流
    • DataInputStream :处理流更改构造方法接收一个已经存在的输入流
    • FileReader:从文件中读取字符数据的输入流
    • StringReader:从字符串中的读取字符数据的输入流
    • BufferedReader :字符缓冲输入流
    • InputStreamReader :接受字节输入流并使用指定的字符集将其解码成字符
    • BufferedInputStream :缓冲字节输入流

Files.newInputStream和FileInputStream

  • Files.newInputStream流和FileInputStream的区别
    • Files.newInputStream是jdk1.7引入的属于(New I/O 2)部分,而FileInputStream是属于传统的I/O流类库,从比较早的版本到现在一直都存在
    • API设计:FileInputStream属于传统的API相对简单一点而Files.newInputStream有着更高的特性
      • Files.newInputStream更高的特性体现于可以灵活的路径处理,它的参数是Path对象,并不是直接的文件路径字符串,这也就意味着可以使用更灵活的路径操作
        列子: 两种运用方式
try (InputStream inputStream = Files.newInputStream(Paths.get("path.xml"))) {
    // 读取数据的逻辑
} catch (IOException e) {
    e.printStackTrace();
}

又或者

Path path=Paths.get("path.xml");
try (InputStream inputStream = Files.newInputStream(path)) {
    // 读取数据的逻辑
} catch (IOException e) {
    e.printStackTrace();
}

更多的文件操作的方法,比如Files.copy,Files.Move
列子: 将源文件复制到目标文件

try  {
    Files.copy(Paths.get("path.txt"), Paths.get("test.txt"));
} catch (IOException e) {
    e.printStackTrace();
}

支持更多的选项:StandardOpenOption.READ,StandardOpenOption.WRITE等一系列的选项用于打开文件的指定方式,提供了更多的控制性跟灵活性差

Path path=Paths.get("path.xml");

try (InputStream inputStream = Files.newInputStream(path,StandardOpenOption.CREATE)) {
} catch (IOException e) {
    e.printStackTrace();
}
    • 异常的处理机制
      • FileInputSteram主要抛出FileNotFoundException和IOException
      • Files.newInputStream使用的是NOI.2的异常体系可以抛出IOException和UncheckedIoexception等一系列异常
    • 实现原理:
      • Files.newInputSteram是用过NIO.2中的FileChannel和ByteBuffer实现的,他提供了更灵活更高效的文件I/O的操作,允许对文件进行更多的控制
      • FileInputStream是使用传统的InputStream类库,底层通过本地的文件系统调用实现,较为简单直接从文件输入流中读取字节
    • 优缺点:
      • Files.newInputStream:灵活,异常体系更丰富,对于简单的文件读取任务显得有些过于复杂
      • FileInputStream:对于简单的读取使用起来比较简单直接,就是功能在文件I/O的操作上有相对的限制
    • 文件流读取的几种实现方式


//缓冲流读取,它提供了缓冲区来提高读取的性能。通过包装其他输入流,
try (BufferedInputStream bufferedInput = new BufferedInputStream(Files.newInputStream(Paths.get("example.txt")))) {
    int data;
    while ((data = bufferedInput.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

// Scanner 类可以方便地用于读取各种数据类型,包括基本类型和字符串
try (Scanner scanner = new Scanner(new FileInputStream("example.txt"))) {
    while (scanner.hasNext()) {
        String data = scanner.next();
        System.out.println(data);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

//从底层输入流中读取基本java数据类型
Path path = Paths.get("example.txt");
try (DataInputStream dataInput = new DataInputStream(Files.newInputStream(path))) {
    int data = dataInput.readInt();
    System.out.println(data);
} catch (IOException e) {
    e.printStackTrace();
}

//是用于读取字符流的类,可以用于读取字符文件的内容
try (FileReader fileReader = new FileReader("example.txt")) {
    int data;
    while ((data = fileReader.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

//字符输入流的缓冲,它提供了缓冲区来提高读取字符的性能
try (BufferedReader bufferedReader = new BufferedReader(new FileReader("example.txt"))) {
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

ByteArrayInputStream 流

  • ByteArrayInputStream 是java中的InputStream的一个具体实现,他是从字节数组中读取数据,允许程序已流的方式从内存中的字节数组中读取数据,不需要实际的物理文件或者是网络链家
public class ByteArrayInputStream extends InputStream {
    /**
    * 使用整个字节数组作为输入流
    * buf要读取的字节数组
    */
    public ByteArrayInputStream(byte[] buf)

 
       /**
        * 使用指定区域的字节数组作为输入流
        * buf要读取的字节数组
        * offset 字符数组的起始偏移量
        * length 要读取的字符数
        */

    public ByteArrayInputStream(byte[] buf, int offset, int length)
}


  • ByteArrayInputStream提供了一些方法
    • read()读取下一个字节
    • read(byte[]n,int off,int len):从输入流中读取最多len个字节到字节数组b中 从偏移量off开始存储,返回实际读取的字符数
    • skip(long n ):n就是代表要跳过的数组
    • available():可以从此输入流中读取或跳过 而不会阻塞的剩余字符数
  • 实现原理:ByteArrayInputStream是通过字节数组包装秤输入流的方式实现,其内部维护了一个字节数组,通过指针来记录当时读取的位置,在调用读取方法的时候,他会从字节数组中读取相应的数据,并且更新指针位置
  • 优缺点:
    • 适用于内存中的数据操作 无需依赖外部的文件网络等
    • 他是基于字节数组实现的 相对其他输入流来说ByteArrayInputStream 是一个轻量级的存在
    • 他依赖于一个固定的字节数组,不适用于动态数组或者大型的数据流
    • 一旦字节数组传递给ByteArrayInputStream它的内容就没有办法进行实现了
    • 不支持标记和重置操作
  • 读取方式



//单一读取
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[1024]);
int data;
while ((data = inputStream.read()) != -1) {
    // 处理读取到的字节数据
    System.out.print((char) data);

}
// 关闭输入流
try {
    inputStream.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}


//批量读取
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) {
    // 处理读取到的字节数组数据
    System.out.print((char) bytesRead);


}
// 关闭输入流
try {
    inputStream.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}

DataInputStream 处理流

  • DataInputStream 是java中FilterInputStream类的一个具体实现,用于从输入流中读取基本数据类型,提供了一系列的方法,可以方便的读取不同类型的数据,不需要进行手动数据类型转换
  • 实现原理:DataInputStream是一个装饰器Decorator类 它继承与FilterInputStream 并且实现了DateInput的接口,主要就是对底层的输入流进行包装,他是通过调用基础的输入流读取的方法 然后根据需要将字节数据类型转换为对应的基本数据类型
  • 优缺点:
    • 方便的读取基本的数据类型,避免了手动进行字节到数据类型的转换
    • 适用于数据序列化,提供的方法可以方便的读取和处理数据
    • 异常的处理方式比较简单 具体的错误格式需要额外处理
    • 他主要使用与读取基本数据类型 不太适合复杂的数据类型
    • 具体实现
try (DataInputStream dataInputStream = new DataInputStream(Files.newInputStream(Paths.get("file.txt")))) {
    // 读取不同类型的数据
    boolean booleanValue = dataInputStream.readBoolean();
    byte byteValue = dataInputStream.readByte();
    char charValue = dataInputStream.readChar();
    double doubleValue = dataInputStream.readDouble();
    float floatValue = dataInputStream.readFloat();
    int intValue = dataInputStream.readInt();
    long longValue = dataInputStream.readLong();
    short shortValue = dataInputStream.readShort();
    String stringValue = dataInputStream.readUTF();
} catch (IOException e) {
    e.printStackTrace();
}

FileReader

  • FileReader主要提供了一些用于读取字符的方法 最常用的是read用于读取单个字符
  • 实现原理:基于底层的输入流,它使用了默认的字符编码或者指定的字符编码从文件中读取,在底层中使用了FileInputStream来进行读取字节 然后将字节转为字符
  • 优缺点:
    • 简单容易使用,适合读取文本文件
    • 默认情况下 他是用的系统默认的字符编码 这就导致跨平台可能会有字符棉麻的问题,如果需要指定字符编码建议使用带有字符集的构造方法,不太适合处理二进制数据
  • 读取方式

try (FileReader fileReader = new FileReader("file.txt")) {
    int data;
    while ((data = fileReader.read()) != -1) {
      
        char character = (char) data;
        //输出处理到的数据
        System.out.print(character);
    }
} catch (IOException e) {
    e.printStackTrace();
}

StringReader:

  • StringReader继承于Reader,方便快捷的将字符串写进内存
  • 实现原理:StringReader他是基于Reader抽象类的一个具体实现 在内部它使用一个指针来追踪读取的位置,然后通过相应的方法将字符提供给调用者
  • 优缺点:
    • 方便的读取字符串,不涉及文件系统的操作,适用于读取纯字符串的读取场景
    • 无法处理大批量数据,对大批量数据处理可能会导致内存消耗比较大
  • 具体实现


String inputString = "Hello, StringReader,how are you doing!";
try (StringReader stringReader = new StringReader(inputString)) {
    char[] buffer = new char[10];
    int bytesRead;
    while ((bytesRead = stringReader.read(buffer, 0, buffer.length)) != -1) {
        // 打印读取到的字符数组数据
        System.out.print(new String(buffer, 0, bytesRead));
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedReader

  • 实现原理:
    • BufferedReader的实现主要基于字符输入流Reader 他在内部维护一个字符缓冲流 当调用read() 或readLine()方法时首先先从缓冲里边读取数据,如果缓冲区为空,则从底层Reader读取一批字符到缓冲区,然后再从缓冲区返回数据
  • 优缺点
    • 缓冲机制可以提高读取的性能,减少底层的读取次数 提供了方便的readLine()方法可以逐行读取文本数据
    • 不适合二进制数据,他主要用于文本数据

 String fileName = "file.txt";

   try (BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                // 打印读取到的行数据
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

InputStreamReader

  • 实现原理:主要就是基于inputStream 在内部它使用了Charset进行处理字符编码的转换 再调用read方法的时候 他会从底层的输入流读取字节数据 然后根据指定的字符集解码为字符
  • 主要提供了方便的字符编码转换,将字节流转换成了字符流 解决了字符集不一致的问题,比较适合多语言的环境,但是在进行字符编码转换的会带来一定的开销,在大批量的数据情况下开销会更大
  • 代码实现

String fileName = "file.txt";
try (InputStream inputStream = Files.newInputStream(Paths.get(fileName));
     //指定字符集 将流放到 InputStreamReader中
     InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
    //转成字符流
     BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        // 处理读取到的行数据
        System.out.println(line);
    }
} catch (IOException e) {
    log.info(e.getMessage());
}

BufferedInputStream

  • BufferedInputStream是缓冲字节输入流 他提供了对底层输入流的缓冲功能,可以显著提高读取性能,他是继承自FilterInputStream包装了其他的输入流 并且添加了缓冲功能
  • 实现原理:BufferedInputStream树妖基于底层的InputStream 他在内部维护了一个字节缓冲区(Byte[]数组) 当调用read方法时 首先从缓冲区读取数据,如果缓冲区数据为空则从底层的输入流中读取一批字节到缓冲区,然后再从缓冲区返回数据,这种机制可以减少对底层输入流的实际读取次数,从而提高性能
  • 优缺点:
    • 缓冲机制可以显著提高读取性能,减少底层读取次数,适用于大批量数据或者网络数据流,可以一次性读取较大的字节数组
    • 对实时更新要求较高的不太实用,缓冲区的引入可能会导致数据的延迟
  • 代码实现

String fileName = "file.txt";

try (InputStream inputStream = Files.newInputStream(Paths.get(fileName));
     BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {

    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
        // 处理读取到的字节数组数据
        System.out.write(buffer, 0, bytesRead);
    }
} catch (IOException e) {
    log.info(e.getMessage());
}

OutputStream

输出流的层次结构

  • 字节输出流(Byte Output Stream) 和字符输出流(cHARACTER Output Stream)
    • FileOutputStream :文件输出
    • DataOutputStream:输出流基本数据类型的写入
    • BufferedOutputStream:通过包装其他的字节输出流,提供了缓冲功
    • ByteArrayInputStream:从字节数组中读取数据
    • OutputStreamWriter:字节流到字符流的桥梁,将字节流转换为字符流
    • FileWriter:写入字符文件的便利类
    • BufferedWriter:用于写入字符数据的缓冲字符输出流
    • StringWriter:字符数据写入该缓冲区

FileOutPutStream

  • FileOutPutStream:继承于OutputStream 提供了一些写入字节数据的方法,fileOutputStream实现基于底层的文件输出流,通过底层的文件系统api时间线将自己写入文件,再底层使用了FIleDescriport和本地系统调用来进行实现文件的写入
  • 优缺点:
    • FileOutputStream提供了灵活的方法,可以方便的将字节数组,单个字节或者部分字节,比较适合处理大文件
  • 针对文本的处理需要额外的字符编码操作,,不太适合用于处理字符
  • 在处理异常的时候需要额外的代码,容易忽略文件的关闭操作,最好是使用try异常处理机制,使用完确保正确的关闭流
  • 代码实现

try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt")) {
    // 写入字节数组
    byte[] data = "Hello, FileOutputStream!".getBytes();
    fileOutputStream.write(data);

    // 刷新并关闭流
    fileOutputStream.flush();
} catch (IOException e) {
    e.printStackTrace();
}

DateOutputStream

  • 实现原理:他通过底层的输出流实现对基本数据类型的写入,在写入的时候会将java的基本数据类型转为数组,并通过底层的输出流写入这些字节数组
  • 优缺点
    • 方便写入基本数据类型,可以方便的将基本数据类型以一定的格式写入输出流量,适用于与其他系统做的数据交换
    • 不太适用于文本数据,因为他主要设计是用于写入基本数据类型的

try (DataOutputStream dataOutputStream = new DataOutputStream(Files.newOutputStream(Paths.get(fileName)))) {
    // 写入基本数据类型
    dataOutputStream.writeInt(42);
    dataOutputStream.writeDouble(3.14);
    dataOutputStream.writeUTF("Hello, DataOutputStream,how are you doing!");

    // 刷新并关闭流
    dataOutputStream.flush();
} catch (IOException e) {
    e.printStackTrace();
}

BufferedOutputStream

  • BufferedOutputStream的实现主要基于底层的输出流,在内部维护了一个字节缓冲区,当调用write方法的时候,会首先将数据写入缓冲区中,当缓冲区或者是手动调用flush方法时才会将缓冲区的数据写入底层的输出流
  • 优缺点
    • 缓冲机制可以显著的提高写入的性能,减少实际的底层写入的次数,适用于处理大文件或者网络数据流
    • 缓冲区的引入可能会造成数据的演出

try (OutputStream outputStream = Files.newOutputStream(Paths.get("file.txt"));
     BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {

 byte[] data = "Hello, BufferedOutputStream!".getBytes(); bufferedOutputStream.write(data);

    // 刷新并关闭流
  bufferedOutputStream.flush();
} catch (IOException e) {
  log.info(e.getMessage());
    e.printStackTrace();
}

ByteArrayInputStream

  • ByteArrayInputStream的实现主要是基于内部的字节数组,在创建ByteArrayInputStream对象的时候将字节数组传入构造方法,该字节数组九城了输入流的数据源,再度取得时候在内部使用指针来进行追踪读取的位置,没读取一次,指针向前移动一次
  • 处理的机制;读取字节->读取字节数组
  • 优缺点
    • 适用于在内存中进行操作,不需要外部文件跟网络交互 他由于数据源在内存当中 读取的速度会很快
    • 内存消耗的比较大,不太适合动态追加数据,因为数据源是提前存在的字节数组

byte[] data = {72, 101, 108, 108, 111}; // ASCII codes for 'H', 'e', 'l', 'l', 'o'

try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) {
    int byteRead;
    while ((byteRead = byteArrayInputStream.read()) != -1) {
        // 处理读取到的字节
        System.out.print((char) byteRead);
    }
} catch (IOException e) {
    log.info(e.getMessage())
    e.printStackTrace();
}

OutputStreamWriter

  • OutputStreamWriter是字节流到字符流中间的桥梁,用于将字节流转为字符流,它继承的是writer,构造方法中可以指定字符编码,用于将字节按照指定的编码格式转为字符
  • 在创建OutputStreamWriter的时候需要指定底层的字节输出流(OutputStream)和字符编码,OutputStreamWriter的实现机制就是将写入OutputStreamWriter的字符按照指定的字符编码进行转换,然后在通过字节输入流将东西写入到文件或者网络等
  • 优缺点:
    • 提供了特别方便的字符编码的转换,适合处理文本数据的场景
    • 性能的开销会比较大

try (OutputStream outputStream = Files.newOutputStream(Paths.get("example.txt"));
     OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {

    // 写入字符数据
    String data = "Hello, how are you?!";
    outputStreamWriter.write(data);

    // 刷新并关闭流
    outputStreamWriter.flush();
} catch (IOException e) {
    log.info(e.getMessage())
    e.printStackTrace();
}

FileWriter

  • 它的实现就是将字符按照默认的编码转成字节 然后通过FineOutputStream写到文件中
  • 在创建FileWriter的时候可以指定文件名或者文件对象,也可以选择是否在文件末尾追加
  • 优缺点:
    • 操作简单,不需要手动的转换成字节,特别适用于文本数据
    • 默认的字符编码可能会导致跨平台环境下的问题,性能的开销比较大

try (FileWriter fileWriter = new FileWriter("file.txt")) {

    // 写入字符数据
    String data = "Hello, how are you?!";
    fileWriter.write(data);

    // 刷新并关闭流
    fileWriter.flush();
} catch (IOException e) {
    log.info(e.getMessage());
    e.printStackTrace();
}

BufferedWriter

  • BufferedWriter在写入的时候会将数据先存放在内部缓存区,然后手动调用flush方法或者是缓冲区满的时候,将缓冲区的数据写到字符输出力汇总
  • 优缺点:
    • 缓冲机制有着显著的提高写入的性能,减少了实际的底层写入的次数,特别适用于大量的数据
    • 因为缓冲机制写入有可能会造成数据的不实时性

try (FileWriter fileWriter = new FileWriter("file.txt");
     BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {

    // 写入字符数据
    String data = "Hello, how are you?!";
    bufferedWriter.write(data);

    // 刷新并关闭流
    bufferedWriter.flush();
} catch (IOException e) {
    log.info(e.getMessage());
    e.printStackTrace();
} 

StringWriter

  • StringWriter的实现机制就是在内部维护了一个StirngBuffer对象 在调用write方法时候写入,实际就是将字符数据追加到内部的StringBuffer中
  • 优缺点
    • 方便的构建字符串,适合用于文本操作
    • 不太适合处理大量的数据
try (StringWriter stringWriter = new StringWriter()) {

    // 写入字符数据
    stringWriter.write("Hello, how are you ?!");

    // 获取构建的字符串
    String result = stringWriter.toString();
    System.out.println(result);

} catch (IOException e) {
    log.info(e.getMessage());
    e.printStackTrace();
}

总结

提示:java进阶之路学习笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值