Java 字节流的基本使用

文章目录

  • 字节流
    • FileInputStream & FileOutputStream
      • `FileInputStream`
      • `FileOutputStream`
      • 配合使用
    • BufferedInputStream 和 BufferedOutputStream
      • `BufferedInputStream`
      • `BufferedOutputStream`
    • ByteArrayInputStream和ByteArrayOutputStream
      • `ByteArrayInputStream`
      • `ByteArrayOutputStream`
    • DataInputStream与DataOutputStream
    • ObjectInptStream和ObjectOutputStream

为了提高文章的可阅读性,在本文的示例程序中,对于异常的处理采取了直接抛出,减少了try/catch,使得代码简凑易读。请读者在实操时用try/catch代码块进行处理!

字节流

FileInputStream & FileOutputStream

下面介绍这两个类的使用
新建一个文件"C_01.txt",写入Morning!,共8个字节

FileInputStream

FileInputStream对象在创建时与文件建立了连接,用于从文件中读取原始字节流,因此不适合读取含有非单字节编码的符号(如中文)的文件。

1.流对象与文件建立连接

FileInputStream in = new FileInputStream(new File("C_01.txt"));

2.返回剩余可以被读取(或跳过)的字节数

System.out.println(in.available()); //8

3.判断流对象是否支持mark和reset

System.out.println(in.markSupported()); //false

4.读取并返回下一个字节

 int read = in.read();
 System.out.println((char)(read));   //M
  1. 读取字节流存入bytes数组 最多读入bytes.length大小的内容,返回读取的字节数
byte[] bytes = new byte[10];
System.out.println(in.read(bytes));		//8
System.out.println(new String(bytes));//Morning!  

6.读取指定长度的字节,从字节数组的的指定偏移量开始存放,,返回读取的字节数

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

byte[] bytes = new byte[20];                          
System.out.println(in.read(bytes,10,3));        //3   
System.out.println((char)bytes[10]);    //M           
System.out.println((char)bytes[12]);    //r           

7.返回剩余的字节组成的字节数组

byte[] bytes = in.readAllBytes();
System.out.println(new String(bytes));  //Morning!

8.读取指定长度的字节,从字节数组的指定偏移量开始存放,返回读取的字节数

byte[] bytes = new byte[20];
int len = in.readNBytes(bytes,0,2);
System.out.println(len);        //2
System.out.println(new String(bytes));  //Mo

9.读取指定长度的字节,返回一个字节数组

byte[] bytes = in.readNBytes(7);
System.out.println(bytes.length);   //7
System.out.println(new String(bytes));  //Morning

10.跳过n个字节

in.skip(7);
System.out.println((char)in.read());    //!
in.close();

11.关闭流并释放资源

in.close();

FileOutputStream

FileOuputStream对象用于向文件写原始入字节。注意,有些系统不支持多个FileOutputStream对象同时对同一个文件进行写入。

1.流对象与文件建立连接

FileOutputStream out = new FileOutputStream(new File("C_01.txt"));

2.向文件中写入字节数组bytes的内容,C_01.txt内容变为Hello World

byte[] bytes = "Hello World".getBytes();
out.write(bytes);
out.flush();        //强制刷新,使得流中的数据输入文件

3.将bytes数组从偏移量6开始的5个字节内容写入文件,C_01.txt内容变为World

byte[] bytes = "Hello World".getBytes();
out.write(bytes,6,5);
out.flush();

4.将指定字节写入文件,C_01.txt内容变为e

byte[] bytes = "Hello World".getBytes();
out.write(bytes[1]);

配合使用

输入流与a.txt建立连接,输出流与b.txt建立连接,通过输入流的transferTo方法,将a文件的字节传输到b文件,并返回传输的字节数量

in = new FileInputStream(new File("a.txt"));
out = new FileOutputStream(new File("b.txt"));
System.out.println(in.transferTo(out)); //返回传输的字节数量

BufferedInputStream 和 BufferedOutputStream

BufferedInputStream

BufferedInputStream对象中包含了一个内置的数组;同时,它拥有mark和reset的功能–就像是一个指针,标记了流中的一个位置,调用reset后,会回到该位置

1.与FileInputStream使用方式一样的API,不再赘述
C_03_1.txt文件中写有Morning!

InputStream in = new FileInputStream(new File("C_03_1.txt"));
BufferedInputStream bufferedInputStream = new BufferedInputStream(in);

System.out.println(bufferedInputStream.available());    //8
System.out.println(bufferedInputStream.markSupported()); //true
byte[] bytes = bufferedInputStream.readAllBytes();
System.out.println(new String(bytes));            //Morning!

2.markreset

System.out.println((char) bufferedInputStream.read());//M
//传入的参数是:调用mark()方法之后到调用reset()方法失败之前,允许的最大预读数
bufferedInputStream.mark(0);
System.out.println((char) bufferedInputStream.read());//o
System.out.println((char) bufferedInputStream.read());//r
//返回mark的位置
bufferedInputStream.reset();
System.out.println((char) bufferedInputStream.read());//o

BufferedOutputStream

通过使用BufferedOutputStream对象 应用程序可以将字节写入底层输出流(如FileOutputStream),而不必对写入的每个字节都导致对底层系统的调用。

该类的使用与FileOutputStream相似,不再赘述

OutputStream out = new FileOutputStream(new File("C_03_2.txt"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out);

//将Microsoft写入C_03_2.txt中
bufferedOutputStream.write("Microsoft".getBytes());
bufferedOutputStream.flush();
bufferedOutputStream.close();

ByteArrayInputStream和ByteArrayOutputStream

ByteArrayInputStream

ByteArrayInputStream对象建立的是与byte数组的“连接”,也就是对原生数组的包装。通过阅读其构造函数的源代码即可发现这一点。
因此,调用此类对象的close()方法是不起效果的

构造函数源代码:

 public ByteArrayInputStream(byte buf[]) {
        this.buf = buf;		//让内置的buf引用指向传入的数组
        this.pos = 0;		//维护下一个要访问的位置的“指针”
        this.count = buf.length;
    }
public ByteArrayInputStream(byte buf[], int offset, int length) {
        this.buf = buf;
        this.pos = offset;
        this.count = Math.min(offset + length, buf.length);
        this.mark = offset;
    }

因此,ByteArrayInputStream类的使用也是很简单的

byte[] bytes = "China".getBytes();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
System.out.println(byteArrayInputStream.markSupported());       //true

System.out.println((char) byteArrayInputStream.read());         //C
byteArrayInputStream.mark(0);
System.out.println((char) byteArrayInputStream.read());         //h
System.out.println((char) byteArrayInputStream.read());         //i
byteArrayInputStream.reset();
System.out.println((char) byteArrayInputStream.read());         //h

ByteArrayOutputStream

还是通过构造器的源码来看这个类

//创建构造方法参数指定大小的内置数组
 public ByteArrayOutputStream(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + size);
        }
        buf = new byte[size];
    }

//若不传入参数,则默认创建32字节大小的内置数组
public ByteArrayOutputStream() {
        this(32);
    }

下面是ByteArrayOutputStream的用法

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(16);
//向内置数组写入数据
byteArrayOutputStream.write(65);        //写入A
byteArrayOutputStream.write(66);        //写入B
byteArrayOutputStream.writeBytes("ab".getBytes());  //写入ab

System.out.println(byteArrayOutputStream.size());       //4
System.out.println(byteArrayOutputStream.toString());   //ABab
System.out.println(new String(byteArrayOutputStream.toByteArray()));    //ABab

        
FileOutputStream fileOutputStream = new FileOutputStream(new File("C_02.txt"));
byteArrayOutputStream.writeTo(fileOutputStream);        //将内置数组的内容通过fileOutputStream写入C_02.txt

DataInputStream与DataOutputStream

DataInputStream类对象使得程序可以从InputStream流中读取Java原生类型,对应的也就是DataOutputStream对象可以向流中写入Java原生类型。注意:读和写必须遵循一样的顺序与类型!

以下程序通过DataOutputStream通过OuputStream流,向文件中写入三个Java原生数据类型的数,再通过DataInputStream读出

File file = new File("C_04.txt");
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file);

DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);

//向C_04.txt写入三个Java原生类型的数据
dataOutputStream.writeBoolean(true);
dataOutputStream.writeInt(888);
dataOutputStream.writeLong(999L);
fileOutputStream.flush();

//从C_04.txt中读出原生数据
System.out.println(dataInputStream.readBoolean());  //true
System.out.println(dataInputStream.readInt());      //888
System.out.println(dataInputStream.readLong());     //999

ObjectInptStream和ObjectOutputStream

如果理解了DataInpuStream和DataOutputStream的作用,那么接下来这两个类也自然好理解了。

ObjectOutputStream通过OuputStream向文件中写入序列化的对象或Java原生类型,相当于是序列化的过程。而ObjectInpuStream通过InpuStream从文件中读出内容,经过反序列化,还原出对象或原生Java类型。

下面这个例子,将Car对象通过ObjectOutputStream序列化写入文件,再通过ObjectInputStream反序列化读出。
其中Car和Engine对象是两个普通的Java bean,Engine与Car是组合关系。

        //1.序列化存入
        //创建一个对象car
        Car car = new Car("BWM",10000.983D,new Engine("发动机A",100.10D));
        File file = new File("C_05.txt");
        FileOutputStream fileOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file);
            objectOutputStream = new ObjectOutputStream(fileOutputStream);
            //向文件中写入car
            objectOutputStream.writeObject(car);
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                objectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


        //2.反序列化读出
        FileInputStream fileInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            objectInputStream= new ObjectInputStream(fileInputStream);
            //从文件中读出car
            Object obj = objectInputStream.readObject();
            Car c = (Car)obj;
            System.out.println(c);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                objectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

你可能感兴趣的:(java)