JavaIO流-IO 流

一、IO 流

1.1、IO 流概述和分类

1.1.1、IO 流概述

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

1.1.2、IO 流分类

  • 按照数据的流向:
    • 输入流:读数据
    • 输出流:写数据
  • 按照数据类型来分:
    • 字节流:
      • 字节输入流
      • 字节输出流
    • 字符流:
      • 字符输入流
      • 字符输出流

1.2、字节流

1.2.1、字节流概述

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

1.2.2、字节流写数据

  • 使用字节输出流写数据的步骤:
    • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
    • 调用字节输出流对象的写数据方法
    • 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

1.2.2.1、FileOutputStream() 构造方法

  • FileOutputStream:文件输出流用于将数据写入 File
    • FileOutputStream​(String name):创建文件输出流以指定的名称写入文件
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt");
/*
    做了三件事情:
        A:调用系统功能创建了文件
        B:创建了字节输出流对象
        C:让字节输出流对象指向创建好的文件
  */
// void write​(int b)
fos.write(97);
fos.close();

1.2.2.2、字节流写数据的 3 种方式

方法名 说明
void write(int b) 将指定的字节写入此文件输出流
void write(byte[] b) 将 b.length 字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据
void write(byte[] b,int off,int len) 将 len 字节从指定的字节数组开始,从偏移量 off 开始写入此文件输出流一次写一个字节数组的部分数据
1.2.2.2.1、write(int b)
  • 将指定的字节写入此文件输出流。
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt");

// 写入元素
fos.write(97);
fos.write(98);
fos.write(99);
fos.write(100);
fos.write(101);

// 释放资源
fos.close();
1.2.2.2.2、write(byte[] b)
  • 将 b.length 字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据。
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt");

// 写入元素

byte[] bys = {99,97,92,100,123};
// byte[] getBytes():返回字符串对应的字节数组
byte[] bys = "abcde".getBytes();

fos.write(bys);

// 释放资源
fos.close();
1.2.2.2.3、write((byte[] b,int off,int len)
  • 将 len 字节从指定的字节数组开始,从偏移量 off 开始写入此文件输出流一次写一个字节数组的部分数据。
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt");

// 写入元素
byte[] bys = "javase".getBytes();
fos.write(bys,0,bys.length);

// 释放资源
fos.close();

1.2.2.3、字节流写入数据的两个小问题

1.2.2.3.1、字节流写数据如何实现换行
  • 在写入数据后,追加换行符
    • Windows:\r\n
    • Linst:\n
    • Mac:\r
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt");

// 写入元素
for (int i = 0; i < 10; i++) {
    fos.write("java".getBytes());
    fos.write("\r\n".getBytes());
}

// 释放资源
fos.close();
1.2.2.3.2、字节流写数据如何实现追加写入
  • public FileOutputStream​(String name,boolean append):创建文件输出流以指定的名称写入文件。 如果第二个参数为true ,则字节将写入文件的末尾而不是开头
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream(".\\fos.txt",true);

// 写入元素
for (int i = 0; i < 10; i++) {
    fos.write("java".getBytes());
    fos.write("\r\n".getBytes());
}

// 释放资源
fos.close();

1.2.2.4、字节流写数据加异常处理

  • finally:在异常处理时提供 finally 块来执行所有清除操作。比如说 IO 流中的资源释放
    • 特点:被 finally 控制的语句一定会执行,除非 JVM 退出
FileOutputStream fos = null;
try {
    // 创建字节输出流对象
    fos = new FileOutputStream(".\\fos.txt", true);

    // 写入元素
    fos.write("hello".getBytes());
}catch (IOException e){
    e.printStackTrace();
}
finally {
    if ( fos != null) {
        // 释放资源
        fos.close();
    }
}

1.2.3、字节流读数据

1.2.3.1、FileInputStream​() 构造方法

  • public FileInputStream​(String name):通过打开与实际文件的连接创建一个FileInputStream ,该文件由文件系统中的路径名称为name命名。
// 创建字节输入流对象
FileInputStream fis = new FileInputStream(".\\fos.txt");

// 调用字节输入流对象的读数据方法
// int by = fis.read();
// while (by != -1){
//  System.out.print((char) by);
//  by = fis.read();
// }

// 优化上面的代码
/*
    fis.read():读数据
    by = fis.read():把读取到的数据赋值给 by
    by != -1:判断读取到的数据是否是 -1
  */
int by;
while ((by = fis.read()) != -1){
    System.out.print((char)by);
}

// 释放资源
fis.close();

1.2.3.2、字节流读数据的 3 种方法

1.2.3.3、read​()
  • 从该输入流读取一个字节的数据。
// 创建字节流输入对象
FileInputStream fis = new FileInputStream("D:\\fos.txt");

int len = fis.read();
  // 把 整数 强制转换为 字符
System.out.println((char)len);

// 释放资源
fis.close();
1.2.3.4、read​(byte[] b)
  • 从该输入流读取最多b.length个字节的数据为字节数组。
// 创建字节流输入对象
FileInputStream fis = new FileInputStream("D:\\fos.txt");

// public int read​()
byte[] by = new byte[5];
int len = fis.read(by);
  // 把 数组 转换为 字符串
System.out.println(new String(by));

// 释放资源
fis.close();
1.2.3.4、read​(byte[] b,int off,int len)
  • 从该输入流读取高达len字节的数据到字节数组。
// 创建字节流输入对象
FileInputStream fis = new FileInputStream("D:\\fos.txt");

byte[] by = new byte[10];
int len = fis.read(by);
System.out.print(new String(by,0,len));

// 释放资源
fis.close();

1.2.4、字节缓冲流

1.2.4.1、字节缓冲流构造方法

  • 字节缓冲输出流:BufferedOutputStream​(OutputStream out)
  • 字节缓冲输入流:BufferedInputStream​(InputStream in)
1.2.4.1.1、字节缓冲输出流
  • BufferedOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(".\\bos.txt"));

// 写数据
bos.write("hello\r\n".getBytes());

// 释放资源
bos.close();
1.2.4.1.2、字节缓冲输入流
  • BufferedInputStream: 创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
// 创建字节输入流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\\bos.txt"));

// 一次读一个字节数据
//  int by;
//  while ((by = bis.read()) != -1) {
//    System.out.print((char) by);
//  }

// 一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
    System.out.println(new String(bys, 0, len));
}

// 释放资源
bis.close();

1.2.5、字节流读写数据速度

  • 基本字节流一次读写一个数组 比 基本字节流一次读写一个字节字节 块。
  • 字节缓冲流一次读写一个数组 比 字节缓冲流一次读写一个字节字节 块。
  • 字节缓冲流 比 基本字节流 块。

1.3、字符流

1.3.1、为什么会出现字符流

  • 由于字节流操作中文不是特别的方便,所以 Java 就提供字符流
    • 字符流 = 字节流 + 编码表
  • 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别中文呢?
    • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

1.3.2、字符串中的编码解码问题

1.3.2.1、编码

  • 编码:
    • byte[] getBytes():使用平台的默认字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中。
    • byte[] getBytes(String charsetName):使用指定的字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中。
// byte[] getBytes()
String s = "中国";
byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys));

// byte[] getBytes(String charsetName)
String s = "中国";
byte[] bys = s.getBytes("GBK");
System.out.println(Arrays.toString(bys));

1.3.2.2、解码

  • 解码:
    • String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String。
    • String(byte[] bytes,String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String。
// String(byte[] bytes)
byte[] b = {-28, -72, -83, -27, -101, -67};
String ss = new String(b);
System.out.println(ss);

// String(byte[] bytes,String charsetName)
byte[] b = {-28, -72, -83, -27, -101, -67};
String ss = new String(b,"UTF-8");
System.out.println(ss);

1.3.3、字符流中的编码解码问题

  • 字符流抽象基类

    • Writer:字符输出流的抽象类
    • Reader:字符输入流的抽象类
  • 字符流中和编码解码相关的两个类:

    • OutputStreamWriter
    • InputStreamReader

1.3.3.1、OutputStreamWriter 构造方法

它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

1.3.3.1.1、OutputStreamWriter​(OutputStream out)
  • 创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
osw.write("中国");
osw.close();
1.3.3.1.2、OutputStreamWriter​(OutputStream out, String charsetName)
  • 创建一个使用命名字符集的OutputStreamWriter。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"),"GBK");
osw.write("中国");
osw.close();

1.3.3.2、InputStreamReader 构造方法

它读取字节,并使用指定的charset将其解码为字符。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

1.3.3.2.1、InputStreamReader​(InputStream in)
  • 创建一个使用默认字符集的InputStreamReader。
// 创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\a.txt"));

// 一次读取一个字符数据
int ch;
while ((ch = isr.read())!= -1){
    System.out.print((char)ch);
}

// 释放资源
isr.close();
1.3.3.2.2、InputStreamReader​(InputStream in, String charsetName)
  • 创建一个使用命名字符集的InputStreamReader。
// 创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\a.txt"),"GBK");

// 一次读取一个字符数据
int ch;
while ((ch = isr.read())!= -1){
    System.out.print((char)ch);
}

// 释放资源
isr.close();

1.3.4、字符流写数据的 5 种方式

方法名 说明
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf,int off,int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str,int off,int len) 写一个字符串的一部分

1.3.4.1、write(int c)

  • 写一个字符
// 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
// 写一个字符
osw.write(97);
// 刷新流
osw.flush();

// 关闭资源
osw.close();

1.3.4.2、write(char[] cbuf)

  • 写入一个字符数组
// 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
// 写入一个字符数组
char[] chs = {'a','b','c','d'};
osw.write(chs);

// 关闭资源
osw.close();

1.3.4.3、write(char[] cbuf,int off,int len)

  • 写入字符数组的一部分
// 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
// 写入字符数组的一部分
char[] chs = {'a','b','c','d','e'};
osw.write(chs,0,chs.length);

// 关闭资源
osw.close();

1.3.4.4、write(String str)

  • 写一个字符串
// 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
// 写入一个字符串
osw.write("abcdef");

// 关闭资源
osw.close();

1.3.4.5、write(String str,int off,int len)

  • 写一个字符串的一部分
// 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(".\\a.txt"));
// 写一个字符串的一部分
osw.write("abcdef",0,"abcdef".length());

// 关闭资源
osw.close();

1.3.5、字符流读数据的 2 种方式

|方法名|说明|
|int read()|一次读一个字符数据|
|int read(char[] cbuf)|一次读一个字符数组数据|

1.3.5.1、read()

  • 一次读一个字符数据。
// 创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\a.txt"));

// 一次读一个字符数据
int ch;
while ((ch=isr.read()) != -1){
    System.out.print((char)ch);
}

// 释放资源
isr.close();

1.3.5.2、read(char[] cbuf)

  • 一次读一个字符数组数据。
// 创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(".\\a.txt"));

// 一次读一个字符数组数据
char[] bys = new char[1024];
int ch;
while ((ch=isr.read(bys))!=-1){
    System.out.print(new String(bys,0,ch));
}

// 释放资源
isr.close();

1.3.6、字符缓冲流

1.3.6.1、字符缓冲流构造方法

1.3.6.1.1、字符缓冲输出流
  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter(".\\aa.txt"));

// 写入数据
bw.write("hello\n");
bw.write("world");

// 释放资源
bw.close();
1.3.6.1.2、字符缓冲输入流
  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader(".\\aa.txt"));

// 一次读写一个字节数据
// int ch;
// while ((ch=br.read())!=-1){
//  System.out.print((char) ch);
// }

// 一次读写一个字节数组
char[] chrs = new char[1024];
int len;
while ((len=br.read(chrs))!=-1){
    System.out.println(new String(chrs,0,len));
}

// 释放资源
br.close();

1.3.7、字符缓冲流特有功能

1.3.7.1、BufferedWriter 特有方法

  • void newLine():写一行行分隔符,行分隔符字符串由系统属性定义。
// 创建字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter(".\\a.txt"));

// 写数据
for (int i = 0; i < 10; i++) {
    bw.write("hello " + i);
    // 写入系统默认的换行符
    bw.newLine();
    // 把缓存种的数据刷到文件中
    bw.flush();
}

// 释放资源
bw.close();

1.3.7.2、BufferedReader 特有方法

  • public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结果已经到达,则为 null。
// 创建字符输入流对象
BufferedReader br = new BufferedReader(new FileReader(".\\a.txt"));

String line;

// 读一行数据数据
while ((line=br.readLine())!=null){
    System.out.println(line);
}


// 释放资源
br.close();

1.4、IO 流小结

1.4.1、字节流小结

小结:字节流可以复制任意文件数据,有 4 种方式一般采用字节缓冲流一次读写一个字节数组的方式。

1.4.2、字符流小结

小结:字符流只能复制文本数据,有 5 种方式,一般采用字符缓冲流的特有功能。

posted @ 2021-02-20 16:03    阅读(64)  评论(0)    收藏  举报