字节流抽象基类

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

2.1字节流写数据

2.1.1字节流输出的构造方法

方法名 说明
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件
FileOuptStream(File file) 创建文件输出流吸入指定的File对象表示文件中

这两个FileOutputStream的区别,先查看FileOutputStream(String name)的源码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Creates a file output stream to write to the file with the
* specified name. A new <code>FileDescriptor</code> object is
* created to represent this file connection.
* <p>
* First, if there is a security manager, its <code>checkWrite</code>
* method is called with <code>name</code> as its argument.
* <p>
* If the file exists but is a directory rather than a regular file, does
* not exist but cannot be created, or cannot be opened for any other
* reason then a <code>FileNotFoundException</code> is thrown.
*
* @param name the system-dependent filename
* @exception FileNotFoundException if the file exists but is a directory
* rather than a regular file, does not exist but cannot
* be created, or cannot be opened for any other reason
* @exception SecurityException if a security manager exists and its
* <code>checkWrite</code> method denies write access
* to the file.
* @see java.lang.SecurityManager#checkWrite(java.lang.String)
*/
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}

如果传入name不为空,就会new File()一个file对象,因此与第二个构造方法直接传入File对象是一样的

  • FileOutputStream(String name):

    • 执行过程
      • 调用系统功能创建了文件
      • 创建了字节输出流对象
      • 字节输出流对象指向创建好的文件
    • void write (int b):将指定的字节流写入次文件输出流
    • void close():关闭此文件输出流并释放与此流相关的任何系统资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.demo.bytes;

import java.io.FileOutputStream;
import java.io.IOException;

/**
* FileOutputStream:文件输出流用于将数据写入File
* <p>
* - FileOutputStream(String name):创建文件输出流以指定的名称写入文件
*
* @author jingLv
* @date 2020/12/01
*/
public class FileOutputStreamDemo01 {

public static void main(String[] args) throws IOException {
// 创建字节流输出对象
FileOutputStream fileOutputStream = new FileOutputStream("java-file-class/java.txt");
// void write (int b):将指定的字节流写入次文件输出流
// 字节97 表示字符 a
fileOutputStream.write(97);
// 释放资源
fileOutputStream.close();
}
}

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

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

2.1.2字节流写数据的3种方式

方法名 说明
void write(int b) 将指定的字节写入此文件输出流
一次写一个字节数据
void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流
一次写一个字节数组数据
void write(byte[] b,int off, int len) 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
一次写一个字节数组的部分数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.demo.bytes;

import java.io.FileOutputStream;
import java.io.IOException;

/**
* 字节流写数据的3种方式
*
* @author jingLv
* @date 2020/12/01
*/
public class FileOutputStreamDemo02 {
public static void main(String[] args) throws IOException {
// 创建字节流输出对象
FileOutputStream fileOutputStream01 = new FileOutputStream("java-file-class/java01.txt");
System.out.println("--------------字节流写入数据第一种---------------");
// 第一种:void write(int b) 将指定的字节写入此文件输出流(一次写一个字节数据)
fileOutputStream01.write(97);
fileOutputStream01.write(98);
fileOutputStream01.write(99);
fileOutputStream01.write(100);
fileOutputStream01.write(101);

FileOutputStream fileOutputStream02 = new FileOutputStream("java-file-class/java02.txt");
System.out.println("--------------字节流写入数据第二种---------------");
// 第二种:void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流(一次写一个字节数组数据)
// 字节数组
byte[] bytes01 = {97, 98, 99, 100, 101};
fileOutputStream02.write(bytes01);

FileOutputStream fileOutputStream03 = new FileOutputStream("java-file-class/java03.txt");
System.out.println("--------------字节流写入数据第三种---------------");
// 第三种:void write(byte[] b,int off, int len) 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流(一次写一个字节数组的部分数据)
byte[] bytes02 = {97, 98, 99, 100, 101};
fileOutputStream03.write(bytes02, 0, bytes02.length);

// 关闭资源
fileOutputStream03.close();
}
}

输出结果是一样的

字节数组,字符串转字节数组

  • byte[] getBytes():返回字符串对应的字节数组(将字符串转为字节数组)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package com.demo.bytes;

    /**
    * @author jingLv
    * @date 2020/11/19
    */
    public class Main {
    public static void main(String[] args) {
    String str = "abcd";
    byte[] bytes = str.getBytes();
    for (byte b : bytes) {
    System.out.print(b + " ");
    }
    }
    }

    输出结果:

    image-20201201114246928

2.1.3字节流写数据的两个小问题

  • 字节流写数据如何实现换行

    • 换行识别
      • Windows:\r\n
      • Linux:\n
      • Mac:\r
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.demo.bytes;

    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
    * 字节流写数据的两个小问题
    * - 字节流写数据如何实现换行
    * - 字节流写数据如何实现追加
    *
    * @author jingLv
    * @date 2020/12/01
    */
    public class FileOutputStreamDemo03 {

    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    FileOutputStream fileOutputStream = new FileOutputStream("java-file-class/javaHello.txt");
    //写数据
    for (int i = 0; i < 10; i++) {
    fileOutputStream.write("hello".getBytes());
    fileOutputStream.write("\r".getBytes());
    }
    //释放资源
    fileOutputStream.close();
    }
    }

  • 字节流写数据如何实现追加

    • 创建字节输出流使用构造函数:FileOutputStream(String name, boolean apped) 创建文件输出流指定名称写入文件,如果第二参数为true,则字节将写入文件的末尾而不是开头
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.demo.bytes;

    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
    * 字节流写数据的两个小问题
    * - 字节流写数据如何实现换行
    * - 字节流写数据如何实现追加
    *
    * @author jingLv
    * @date 2020/12/01
    */
    public class FileOutputStreamDemo03 {

    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    FileOutputStream fileOutputStream = new FileOutputStream("java-file-class/javaHello.txt", true);
    //写数据
    for (int i = 0; i < 10; i++) {
    fileOutputStream.write("hello".getBytes());
    fileOutputStream.write("\r".getBytes());
    }
    //释放资源
    fileOutputStream.close();
    }
    }

    对文件已有内容,在内容末尾进行写入

2.1.4字节流写数据加异常处理

  • finally:在异常处理时提供finally块来执行所有清楚操作,比如IO流中的释放资源

    • 特点:被finally控制的语句一定会执行,除非JVM退出
    1
    2
    3
    4
    5
    6
    7
    try {
    可能出现异常的代码;
    }catch(异常类名 变量名) {
    异常处理的代码;
    }finally {
    执行所有清楚操作;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.demo.bytes;

    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
    * 字节流写数据加异常处理
    *
    * @author jingLv
    * @date 2020/12/01
    */
    public class FileOutputStreamDemo04 {
    public static void main(String[] args) {
    // finally实现释放资源
    FileOutputStream fileOutputStream = null;
    try {
    fileOutputStream = new FileOutputStream("");
    fileOutputStream.write("hello".getBytes());
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    if (fileOutputStream != null) {
    try {
    fileOutputStream.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }

    jdk1.7提供了TWR的语法,简化IO流异常处理

2.2字节流读数据

2.2.1字节流读取数据的方式

方法名 说明
void read(int b) 将指定的字节读取此文件输入流
一次读一个字节数据
void read(byte[] b) 将b.length字节从指定的字节数组读取此文件输入流
一次读一个字节数组数据
void read(byte[] b,int off, int len) 将len字节从指定的字节数组开始,从偏移量off开始读取此文件输入流
一次读一个字节数组的部分数据

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

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

字节数据,字节数组转字符串:

  • String(byte[] bytes) 将字节数组转为字符串
  • String(byte[] bytes, int offset, int length) 将字节数组一部分转为字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.demo.bytes;

/**
* @author jingLv
* @date 2020/11/19
*/
public class Main {
public static void main(String[] args) {
byte[] bytes = {'h', 'e', 'l', 'l', 'o'};
// String(byte[] bytes) 将字节数组转为字符串
System.out.println(new String(bytes));
// String(byte[] bytes, int offset, int length) 将字节数组一部分转为字符串
System.out.println(new String(bytes, 0, 3));
}
}

执行结果:

image-20201202113018094

2.3字节缓冲流

  • BufferedOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStream out)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.demo.bytes;

    import java.io.BufferedOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;

    /**
    * @author jingLv
    * @date 2020/12/04
    */
    public class BufferedOutputStreamDemo {
    public static void main(String[] args) throws IOException {
    // 字节缓冲输出流
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("java-file-class/test.txt"));
    // 写入数据
    bufferedOutputStream.write("hello\r".getBytes());
    bufferedOutputStream.write("world\r".getBytes());
    // 释放资源
    bufferedOutputStream.close();
    }
    }
  • 字节缓冲输入流:BufferedInputStream(InputStream in)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package com.demo.bytes;

    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;

    /**
    * @author jingLv
    * @date 2020/12/04
    */
    public class BufferedInputStreamDemo {

    public static void main(String[] args) throws IOException {
    // 字节缓冲输入流
    BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("java-file-class/test.txt"));
    // 一次读取一个字节数组
    /* int by;
    while ((by = bufferedInputStream.read()) != -1) {
    System.out.println((char) by);
    }*/

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

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

  • 字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作