14_IO_字节流


IO

在这里插入图片描述

IO的分类

按流向分(以内存为参照物)

  • 输出流: 内存—> 磁盘
  • 输入流: 磁盘—> 内存

按照数据类型分

  • 字节流: 逻辑单位是字节,(1B = 8bit 0000 0000)
  • 字符流: 逻辑单位是字符(理解为一种文化符号,abc , “你”, “の”)

4个抽象基类

  • 字节输出流: OutputStream

  • 字节输入流: InputStream

  • 字符输出流: Writer

  • 字符输入流: Reader

一般来讲, 纯文本文件用字符流 .txt .java .cpp

其他情况用字节流(字节流是万能的) .word .ppt .mp4 .mp3 .jpg . png .exe


字节流

字节输出流

抽象基类OutputStream

抽象基类OutputStream的定义此抽象类是表示输出字节流的所有类的父类

继承关系
在这里插入图片描述

成员方法
在这里插入图片描述

FileOutputStream文件字节输出流

用于将数据写入 File

构造方法

FileOutputStream(File file)       // 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

FileOutputStream(File file,  boolean append)       
// 创建一个向指定 File  对象表示的文件中写入数据的文件输出流。

FileOutputStream(String fileName)       // 创建一个向具有指定名称的文件中写入数据的输出文件流。

FileOutputStream(String name,  boolean append)       
// 创建一个向具有指定 name 的文件中写入数据的输出文件流 append 
// - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处

eg:

// 1.
File f = new File("D:\\Java_test\\a.text");
FileOutputStream out1 = new FileOutputStream(f);

// 2.
FileOutputStream out2 = new FileOutputStream(new File("a.txt"));
    
// 3.
FileOutputStream out3 = new FileOutputStream("a.txt");

成员方法

  • 写数据的步骤
      1. 创建输出流对象
      1. write
      1. 释放资源 close

eg:

// 1. 创建输出流对象
FileOutputStream out = new FileOutputStream("a.txt");

// 2.1 write(int b) 写单个字节
out.write(97);

// 2.2 write(byte[] b) 批量写
String s = "hello world";
byte[] bytes = s.getBytes();
out.write(bytes);

// 2.3 write(byte [] b , int off , int len) 写字节数组的部分
out.write(bytes,0,5);

// 3. 释放资源 close
out.close();

注意事项

  • 当我们创建一个输出流对象的时候,发生了什么?
    • jvm向操作系统中看这个文件是否存在
    • 如果文件不存在, 帮我们创建
    • 文件已经存在, 覆盖重新开始写

实现文件追加功能
借助于带append参数的构造方法

eg:

// 使用带append的构造方法
 // 创建输出流对象
 FileOutputStream out = new FileOutputStream("a.txt", true);
// write
out.write(100);
// close
out.close();

实现换行功能
借助于换行符

  • “\r\n”
  • System.lineSeparator()

eg:

// 创建输出流对象
FileOutputStream out = new FileOutputStream("a.txt");
out.write("abcd".getBytes());
// write 写换行符

// \r\n
out.write("\r\n".getBytes());
out.write(97);
        
// 使用系统默认换行符
out.write(System.lineSeparator().getBytes());
out.write(97);

// close
out.close();

异常处理

  1. 采用try-catch-finally

eg:

FileOutputStream out = null;
try {
    out = new FileOutputStream("a.txt");
    out.write("hello world".getBytes());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (out != null) {
            out.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. 采用try-with-resources

语法

try(资源,只要实现了AutoCloseable接口的类){
 //可能出现异常的代码
 // 当出了try代码块的时候 close方法会自动执行 资源会被自动释放
}catch(){
	
}

eg:


try(FileOutputStream out = new FileOutputStream("a.txt")) {
// write数据
	out.write("abc".getBytes());
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

--------------------------------------------------------------------

/*
验证close方法自动执行
 */
public class Demo {
    public static void main(String[] args) {
        try (A a = new A()){
            // 调用func 不调用close
            a.func();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class A implements AutoCloseable{

    @Override
    public void close() throws Exception {
        System.out.println("close执行了");
    }

    public void func(){
        System.out.println("func方法执行了");
    }
}

为什么要close?

  • jvm使用了不属于jvm的资源, 不能通过GC回收, 只能功能close显式的释放资源.

BufferedOutputStream缓冲字节输出流

该类实现缓冲的输出流。
通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

构造方法
(装饰器设计模式)

BufferedOutputStream(OutputStream out)        
// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。默认缓冲区大小是8KB

BufferedOutputStream(OutputStream out, int size)       
// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。指定缓冲区size大小

成员方法

在这里插入图片描述

字节缓冲输出流的步骤

    1. 创建输出流对象
    1. write写数据
    1. flush
    1. close

eg:

// 1. 创建输出流对象
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream("a.txt"));

// 2. write
// write(b)
bufferedOutputStream.write(97);
bufferedOutputStream.write(System.lineSeparator().getBytes());

// write(byte[] b)
bufferedOutputStream.write("yyds".getBytes());
bufferedOutputStream.write(System.lineSeparator().getBytes());

// write(byte[] b, int off, int len)
bufferedOutputStream.write("hello world".getBytes(),0,5);
bufferedOutputStream.write(System.lineSeparator().getBytes());

// 3. flush
bufferedOutputStream.flush();

// 4. close
bufferedOutputStream.close();

字节输入流

抽象基类InputStream

此抽象类是表示字节输入流的所有类的父类。

继承关系
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/74fac6dbdf2c4a68aa48f34b0406401b.png

成员方法
在这里插入图片描述
注意
读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1。返回值表示读取的字节的个数 readCount

FileInputStream文件字节输入流

构造方法

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

FileInputStream(String fileName)        
// 通过打开一个到实际文件的连接来创建一个 FileInputStream,
// 该文件通过文件系统中的路径名  name 指定。

成员方法

读取数据的步骤:

    1. 创建输入流对象
    1. read
    1. close释放资源

eg:

// 1. 创建输入流对象
FileInputStream in = new FileInputStream("a.txt");

// 2.1 read() 读取单字节,返回值是读取到的字节值
int readData = in.read();
System.out.println("readData = " + ((char)readData));

// 2.2 read(byte[] b)
byte[] bytes = new byte[1024];
int readCount = in.read(bytes);
System.out.println("readCount = " + readCount);// 读取到字节的个数

// byte[] ---> String
System.out.println("new String() = " + new String(bytes));

// 2.3 read(byte[],int off,int len)
byte[] bytes1 = new byte[1024];
int readCount1 = in.read(bytes1,2,3);
System.out.println("readCount = " + readCount1);// 读取到字节的个数

// 3. close
in.close();

BufferedInputStream缓冲字节输入流

构造方法
(装饰器设计模式)

BufferedInputStream(InputStream in)        
// 创建一个 BufferedInputStream 并保存其参数,即输入流  in,以便将来使用。默认缓冲区8KB

BufferedInputStream(InputStream in,  int size)       
// 创建具有指定缓冲区大小的 BufferedInputStream  并保存其参数,即输入流 in,以便将来使用。 
// 使用指定的缓冲区

成员方法
在这里插入图片描述

读取数据的步骤

    1. 创建缓存的输入流对象
    1. read
    1. close释放资源

eg:

// 1. 创建输入流对象
BufferedInputStream in =
         new BufferedInputStream(new FileInputStream("a.txt"));

// 2. read
// 2.1 单个读取
int readData = in.read();
System.out.println(readData);

// 2.2 批量
byte[] bytes = new byte[1024];
int readCount = in.read(bytes);
System.out.println(new String(bytes,0,readCount));

// 3. close
in.close();

文件复制功能

思路

  • 读取源文件, 把数据读取到内存里
  • 把内存的数据写到新文件

在这里插入图片描述

eg:

/*
文件的复制
 */

// 1. 创建输入流对象
FileInputStream in = new FileInputStream("a.txt");

// 2. 创建输出流对象
FileOutputStream out = new FileOutputStream("a_Copy.txt");

// 3. 边读边写
// 3.1 单字节复制
long timeStart = System.currentTimeMillis();
int readData;
while ((readData = in.read()) != -1) {
    // 写入
    out.write(readData);
}

// 3.2 字节数组方式复制
int readCount;
byte[] bytes = new byte[1024];
while((readCount = in.read(bytes)) != -1){
    out.write(bytes,0,readCount);
}


long timeEnd = System.currentTimeMillis();
System.out.println(timeEnd - timeStart + "ms");

// 4. 释放资源
in.close();
out.close();

单字节复制还是字节数组方式效率高?

  • 字节数组批量的方式效率高

为什么?

  • 批量的方式会减少跟操作系统的交互

构建文件复制的工具类


import java.io.*;

public class FileUtils {
    public static void copy1(InputStream in, OutputStream out) throws IOException{
        int readData;
        while((readData = in.read()) != -1){
            out.write(readData);
        }
        in.close();
        out.close();
    }



    public static void copy2(InputStream in, OutputStream out) throws IOException{
        int readCount;
        byte[] bytes = new byte[1024];
        while((readCount = in.read(bytes)) != -1){
            out.write(bytes,0,readCount);
        }
        in.close();
        out.close();
    }

}

使用缓冲的输入流复制文件

BufferedInputStream in =
        new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream out =
        new BufferedOutputStream(new FileOutputStream("a_Copy.txt"));

// 利用工具类进行复制
long start = System.currentTimeMillis();

FileUtils.copy1(in,out);
FileUtils.copy2(in,out);

long end = System.currentTimeMillis();

System.out.println(end - start + "ms");

使用字节流复制

文本文件: 正常复制

图片文件: 正常复制

视频文件: 正常复制

  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coo1heisenberg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值