新版Java进阶之Input-Output Stream流

一、什么是Java的IO流?

(1) Java中的IO(输入/输出)流就是处理数据输入和数据输出的抽象类。

(2) Java I/O流中主要分为俩大类:字节流(Byte Streams)和字符流(Character Streams)。

        字节流:主要用于处理二进制数据,包括InputStream 和 OutputStream 俩个主要类和其他子类。

        字符流:⽤于处理⽂本数据,包括Reader和Writer两个主要类及其⼦类。

二、Java输入流InputStream

2.1 InputStream

    是输⼊字节流的⽗类,它是⼀个抽象类(⼀般⽤他的⼦类)。

    在Java中, InputStream 是所有字节输⼊流的超类。

    它定义了字节流输⼊的基本操作,如读取字节、跳过字节和标记/重置流等。

    通过 InputStream ,我们可以从⽂件、⽹络连接或其他数据源中读取字节数据。

2.2 常⻅⽅法

    int read():

        从输⼊流中读取单个字节,返回0到255范围内的int字节值, 字节数据可直接转换为int类型

        如果已经到达流末尾⽽没有可⽤的字节,则返回-1

     int read(byte[] b) :

        从输⼊流中读取最多 b.length 个字节的数据到字节数组 b 中,并返回实际读取的字节数。

        如果因为已经到达流末尾⽽没有更多的数据,则返回-1。

    int read(byte[] b, int off, int len) :

        从输⼊流中读取最多 len 个字节的数据到字节数组 b 中,从 off 指定的偏移量开始存储,并返回 实际读取的字节数。

        如果因为已经到达流末尾⽽没有更多的数据,则返回-1。

    long skip(long n) :

        跳过输⼊流中的 n 个字节。如果实际跳过的字节数⼩于 n ,则可能是因为已经到达流的末尾。

        此⽅法返回实际跳过的字节数。

    int available() :返回可以从此输⼊流中读取的字节数的估计值。

    void close() :关闭此输⼊流并释放与该流关联的系统资源。

2.3 常见子类

 FileInputStream

抽象类InputStream⽤来具体实现类的创建对象, ⽂件字节输⼊流, 对⽂件数据以字节的形式进⾏读 取操作

//常⽤构造函数,传⼊⽂件所在地址
public FileInputStream(String name) throws FileNotFoundException
//常⽤构造函数,传⼊⽂件对象
public FileInputStream(File file) throws FileNotFoundException

ByteArrayInputStream 字节数组输⼊流

ObjectInputStream 对象输⼊流

案例实战:

public class InputStreamDemo {
   public static void main(String[] args) {
       String dir = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11";
       String name = "a.txt";
       File file = new File(dir, name);
       try (InputStream inputStream = new FileInputStream(file)) {
           byte[] buffer = new byte[1024];
           int bytesRead;
           while ((bytesRead = inputStream.read(buffer)) != -1) {
               // 处理读取到的数据(例如打印到控制台)
               System.out.println(new String(buffer, 0, bytesRead));
               //中⽂乱码问题,换成GBK 或者 UTF-8
               //System.out.println(new String(buffer,"UTF-8"));
               //System.out.println(new String(buffer,0, bytesRead,"UTF-8"));
               //System.out.println(new String(buffer, 0, bytesRead));
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

注意:

在上⾯的示例中,使⽤了try-with-resources语句来⾃动关闭 InputStream 。

这是JDK 7及更⾼版本引⼊的⼀个新特性,⽤于确保在不再需要资源时⾃动关闭它们。 

 三、Java输出流OutputStream

3.1 OutputStream

    是输出字节流的⽗类,它是⼀个抽象类,在Java中, OutputStream 是所有字节输出流的超类。

    它定义了字节流输出的基本操作,如写⼊字节、刷新输出流和关闭输出流等。

    通过 OutputStream ,可以将数据写⼊⽂件、⽹络连接或其他数据接收端。

3.2 常见方法

void write(int b) :将指定的字节写⼊此输出流。

void write(byte[] b) :将 b.length 个字节从指定的字节数组写⼊此输出流。

void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len 个字节,从偏移量 off 开始。

void flush():

刷新此输出流并强制写出任何缓冲的输出字节,

进⾏输出时,为了提⾼效率,这些类通常会实现缓存机制。

当调⽤ write() ⽅法写⼊数据时,数据可能并不会⽴即被发送到⽬标位置,⽽是先被存储在内部 缓冲区中。

当缓冲区满或我们显式地调⽤ flush() ⽅法时。

void close() :关闭此输出流并释放与此流相关联的任何系统资源

3.3常见子类

 FileOutputStream ,抽象类⽤来具体实现类的创建对象, ⽂件字节输出流, 对⽂件数据以字节的形式 进⾏输出的操作

//传⼊输出的⽂件地址
public FileOutputStream(String name)
 
//传⼊⽬标输出的⽂件对象
public FileOutputStream(File file) 
//传⼊⽬标输出的⽂件对象, 是否可以追加内容
public FileOutputStream(File file, boolean append)

ByteArrayOutputStream :在内存中创建⼀个缓冲区,所有写⼊流的数据都会置⼊这个缓冲区。

案例代码:

public class OutputStreamExample {  
   public static void main(String[] args) {
    
       String dir = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11";
       String name = "b.txt";
        
       try (OutputStream outputStream = new FileOutputStream(file)) {  
           String data = "Hello, World!";  
           outputStream.write(data.getBytes());  
           outputStream.flush(); // 确保所有数据都写⼊⽂件  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
   }  
}

注意:

在Java中,通常会在以下情况下调⽤ flush() ⽅法:

在完成所有写⼊操作并希望确保所有数据都被发送到⽬标位置时。

在需要在写⼊过程中⽴即看到数据的效果时(例如,在⽹络编程中)。

在关闭输出流之前,以确保所有缓冲的数据都被发送出去。 

 四、Java IO包之缓冲Buffer输入输出流 

1.什么是Buffer?

它是内存空间的⼀部分,在内存空间中预留了⼀定的存储空间

这些存储空间⽤来缓冲输⼊或输出的数据,这部分空间就叫做缓冲区,缓冲区是具有⼀定⼤⼩的

当使⽤缓冲流时,数据⾸先被读写到缓存区中,然后再从缓存区传输到⽬标位置(如⽂件、⽹络等)。

这种⽅式减少了直接对⽬标位置的读写操作,因此提⾼了性能。

2.为什么要使用缓冲区

缓冲,缓和冲击,例如操作磁盘⽐内存慢的很多,所以不⽤缓冲区效率很低,数据传输速度和数据处理 的速度存在不平衡。

⽐如:

        1.每秒要读写100次硬盘,对系统冲击很⼤,浪费了⼤量时间在忙着处理开始写和结束写这两个事件。

        2.所以⽤内存的buffer暂存起来,变成每10秒写⼀次硬盘,数据可以直接送往缓冲区。

⾼速设备不⽤再等待低速设备,对系统的冲击就很⼩,写⼊效率⾼了。

3.Java中的缓冲输⼊流与输出流(提供了四种Buffer流)

BufferedInputStream:缓存输⼊流,封装了InputStream,提供了缓存区来暂存输⼊数据。

BufferedOutputStream:缓存输出流,封装了OutputStream,提供了缓存区来暂存输出数据。

BufferedReader:缓存字符输⼊流,封装了Reader,提供了缓存区来暂存字符输⼊数据。

BufferedWriter:缓存字符输出流,封装了Writer,提供了缓存区来暂存字符输出数据。

采⽤的包装设计模式(锦上添花)

主要特点:由于使⽤了缓存区,因此减少了直接对⽬标位置的读写操作,从⽽提⾼了性能。

4.BufferInputStream 缓冲字节输⼊流

    通过预先读⼊⼀整段原始输⼊流数据⾄缓冲区中,外界对BufferedInputStream的读取操作实际上是在 缓冲区上进⾏,

    如果读取的数据超过了缓冲区的范围,BufferedInputStream负责重新从原始输⼊流中载⼊下⼀截数 据,填充缓冲区

    然后外界继续通过缓冲区进⾏数据读取,避免了⼤量的磁盘IO,原始的InputStream类实现的read是即 时读取的

    因为每⼀次读取都会是⼀次磁盘IO操作(哪怕只读取了1个字节的数据),如果数据量巨⼤,这样的磁 盘消耗⾮常可怕。

    读取可以读取缓冲区中的内容,当读取超过缓冲区的内容后再进⾏⼀次磁盘IO

    载⼊⼀段数据填充缓冲,下⼀次读取⼀般情况就直接可以从缓冲区读取,减少了磁盘IO。

    默认缓冲区⼤⼩是8k, int DEFAULT_BUFFER_SIZE = 8192;

4.1 构造函数
//对输⼊流进⾏包装,⾥⾯默认的缓冲区是8k
public BufferedInputStream(InputStream in);
//对输⼊流进⾏包装,指定创建具有指定缓冲区⼤⼩的
public BufferedInputStream(InputStream in,int size);
4.2 常用方法
/从输⼊流中读取⼀个字节
public int read();
//从字节输⼊流中,给定偏移量offset处开始, 将len字节读取到指定的byte数组中。
public int read(byte[] buf,int off,int len);
//关闭释放资源,关闭的时候这个流即可,InputStream会在⾥⾯被关闭
void close();

案例实战:

创建了⼀个 FileInputStream 并将其包装在 BufferedInputStream 中。

通过 bis.read(buffer) ⽅法,可以从⽂件中读取数据到缓冲区中,并在读取过程中处理这些数据。

在try代码块结束后, BufferedInputStream 和 FileInputStream 都会被⾃动关闭 。

import java.io.*;  
  
public class BufferedInputStreamExample {  
   public static void main(String[] args) {  
       String inputFilePath = "input.txt"; // 假设这个⽂件存在并包含⼀些数据  
       try (FileInputStream fis = new FileInputStream(inputFilePath);  
             BufferedInputStream bis = new BufferedInputStream(fis)) {  
  
           byte[] buffer = new byte[1024];  
           int bytesRead;  
           // 读取数据  
           while ((bytesRead = bis.read(buffer)) != -1) {  
               // 处理读取到的数据(这⾥只是简单地打印出来)  
               System.out.print(new String(buffer, 0, bytesRead));  
           }  
  
           // 注意:由于使⽤了try-with-resources,close()⽅法在这⾥是⾃动调⽤的  
  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
   }  
}
5.BufferOutputStream 缓冲字节输出流

内部使⽤⼀个缓冲区来暂存待写⼊的数据。

当缓冲区满时,或者调⽤ flush() ⽅法时,缓冲区中的数据会被⼀次性写⼊到底层输出流中。

这种机制提⾼了数据写⼊的效率,减少了系统I/O操作的次数。

5.1构造函数
//对输出流进⾏包装,⾥⾯默认的缓冲区是8k
public BufferedOutputStream(OutputStream out);
//对输出流进⾏包装,指定创建具有指定缓冲区⼤⼩的
public BufferedOutputStream(OutputStream out,int size);
5.2常用方法
//向输出流中输出⼀个字节
 public void write(int b);
 //将指定 byte 数组中从偏移量 off 开始的 len 个字节写⼊缓冲的输出流。
 public void write(byte[] buf,int off,int len);
 //刷新此缓冲的输出流,强制使所有缓冲的输出字节被写出到底层输出流中。
 public void flush();
 //关闭释放资源,关闭的时候这个流即可,OutputStream会在⾥⾯被关闭, JDK7新特性try(在这⾥声明的会⾃
动关闭){}
 void close();

案例代码:

在这个例⼦中,创建了⼀个 FileOutputStream 并将其包装在 BufferedOutputStream 中。

在try代码块结束后, BufferedOutputStream 和 FileOutputStream 都会被⾃动关闭,因为它们都实 现了 AutoCloseable 接⼝。 

import java.io.*;  
  
public class BufferedOutputStreamExample {  
   public static void main(String[] args) {  
       String outputFilePath = "output.txt";  
       try (FileOutputStream fos = new FileOutputStream(outputFilePath);  
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {  
  
           // 写⼊数据到缓冲区  
           String data = "Hello, World!";  
           bos.write(data.getBytes());  
  
           // 注意:由于使⽤了try-with-resources,flush()和close()⽅法在这⾥是⾃动调⽤的 
 
  
           System.out.println("数据已成功写⼊⽂件。");  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
   }  
}

注意:

在使⽤完 BufferedOutputStream 后,⼀定要记得关闭它,释放系统资源,通过调⽤ close() ⽅法来 实现关闭操作。

BufferedOutputStream在close()时会⾃动flush

在不调⽤close()的情况下,缓冲区不满,⼜需要把缓冲区的内容写⼊到⽂件或通过⽹络发送到别的机器 时,才需要调⽤flush.

流的关闭顺序: 后开先关, 如果A依赖B,先关闭B 

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值