Java I/O(字节流、字符流与转换流)

**File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成。流分为输入流和输出流。
在java.io包中,流分为两种:字节流与字符流:

  • 字节流:InputStream、OutputStream
  • 字符流:Reader、Writer**
    在这里插入图片描述
    在这里插入图片描述

字节流与字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是经过处理后的操作。
在进行网络数据传输、磁盘数据保存所保存所支持的数据类型只有:字节。

而所有磁盘中的数据必须先读取到内存后才能进行操作,而内存中会帮助我们把字节变为字符。字符更加适合处理中文。

不管使用的是字节流还是字符流,其基本的操作流程几乎是一样的,以文件操作为例。
根据文件路径创建File类对象 ;

  • 根据字节流或字符流的子类实例化父类对象 ;

  • 进行数据的读取或写入操作

  • 关闭流(close())

对于IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)最后必须要进行关闭。

字节输出流(OutputStream)
OutputStream类的定义结构

public abstract class OutputStream implements Closeable, Flushable

OutputStream类实现Closeable, Flushable这两个接口,这两个接口中的方法:

Closeable: public void close() throws IOException;
Flushable: public void flush() throws IOException;

OutputStream类中定义的其他方法:

  • 将给定的字节数组内容全部输出:public void write(byte b[]) throws IOException

  • 将部分字节数组内容输出:public void write(byte b[], int off, int len) throws IOException

  • 输出单个字节:public abstract void write(int b) throws IOException

由于OutputStream是一个抽象类,所以要想为父类实例化,就必须要使用子类。由于方法名称都由父类声明好了,所以我们在此处只需要关系子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream类来处理,这个类的构造方法如下:
接收File类(覆盖):public FileOutputStream(File file) throws FileNotFoundException
接收File类(追加):public FileOutputStream(File file, boolean append)

实现文件的内容输出:

package com.bittech;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Test {
    public static void main(String[] args) throws Exception{
        File file = new File("E:"+File.separator+"1"+File.separator+"test");
        if (!file.getParentFile().exists()) { // 必须保证父目录存在
            file.getParentFile().mkdirs() ; // 创建多级父目录
        }
// OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类
        OutputStream output = new FileOutputStream(file) ;
// 要求输出到文件的内容
        String msg = "我们都是一家人!" ;
// 将内容变为字节数组
        output.write(msg.getBytes());
// 关闭输出
        output.close();
    }
}

在进行文件输出的时候,所有的文件会自动帮助用户创建,不在需要调用createFile()方法手工创建。
这个时候程序如果重复执行,并不会出现内容追加的情况而是一直在覆盖。如果需要文件内容追加,则需要调用FileOutputStream提供的另外一种构造方法。

文件内容的追加:

package www.bittech;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Test {
    public static void main(String[] args) throws Exception{
        File files=new File("E:"+File.separator+"1"+File.separator+"test.txt");
        if(!files.getParentFile().exists()){// 必须保证父目录存在
            files.getParentFile().mkdirs();//创建多级父目录
        }
        //OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类
        OutputStream out=new FileOutputStream(files,true);
        //// 要求输出到文件的内容
        String msg="快快乐乐的一家人!\n";
        //将内容变为字节数组
        out.write(msg.getBytes());
        //// 关闭输出
        out.close();
    }
}

1.输出流如果文件不存在,自动创建
2.FileOutputStream中 append默认是false会覆盖内容,若为true,则字节写入文件的末尾而不是开头。

AutoCloseable自动关闭支持
从JDk1.7开始追加了一个AutoCloseable接口,这个接口的主要目的是自动进行关闭处理,但是这种处理一般不好用,因为使用它必须结合try…catch。

AutoCloseable接口使用:

package www.bittech;

class Message implements AutoCloseable{
    public Message(){
        System.out.println("创建一条新消息!");
    }
    public void close() throws Exception{
        System.out.println("[AutoCloseable自动关闭方法!]");
    }
    public void print(){
        System.out.println("www.bittech");
    }
}
public class Test {
    public static void main(String[] args) {
        try (Message msg=new Message()){//必须在try中定义对象
            msg.print();
        }catch (Exception e){

        }
    }
}

推荐使用close手工关闭!

字节输入流:InputStream
利用了OutputStream实现了程序输出内容到文件的处理,下面使用InputStream类在程序中读取文件内容。
InputStream类的定义如下:

public abstract class InputStream implements Closeable

InputStream类只实现了Closeable接口,在InputStream类中提供有如下方法:

  • 读取数据到字节数组中,返回数据的读取个数。如果此时开辟的字节数组大小大于读取的数据大小,则返回的就是读取个数;如果要读取的数据大于数组的内容,那么这个时候返回的就是数组长度;如果没有数据了还在读,则返回-1: public int read(byte b[]) throws IOException.最常用方法
  • 读取部分数据到字节数组中,每次只读取传递数组的部分内容,如果读取满了则返回长度(len),如果没有读取满则返回读取的数据个数,如果读取到最后没有数据了返回-1:public int read(byte b[], int off,int len) throws IOException
  • 读取单个字节,每次读取一个字节的内容,直到没有数据了返回-1:public abstract int read() throws IOException;同OutputStream的使用一样,InputStream是一个抽象类,如果要对其实例化,同样也需要使用子类。如果要对文件进行处理,则使用FileInputStream类。

实现文件信息的读取:

package www.bittech;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Test {
    public static void main(String[] args) throws Exception{
        File file=new File("E:"+File.separator+"1"+File.separator+"test");
        if(file.exists()) {
            InputStream input = new FileInputStream(file);
            byte[] date = new byte[1024];//每次可以读取的最大数量
            int len = input.read(date);//此时数据读取到数组中
            String result=new String(date,0,len);//将字节数组转换为String
            System.out.println(result);
            input.close();
        }
    }
}

字符输出流:Writer
字符适合于处理中文数据,Writer是字符输出流的处理类,这个类的定义如下:

public abstract class Writer implements Appendable, Closeable, Flushable

与OutputStream相比多了一个Appendable接口。
在Writer类里面也提供write()方法,而且该方法接收的类型都是char型,要注意的是,Writer类提供了一个直接输出字符串的方法:

public void write(String str) throws IOException

通过Writer实现输出:

package www.bittech;

import java.io.File;
import java.io.Writer;
import java.io.FileWriter;


public class Test {
    public static void main(String[] args) throws Exception{
        File file=new File("E:"+File.separator+"1"+File.separator+"test.txt");
        if(!file.getParentFile().exists()){//必须保证父目录存在
            file.getParentFile().mkdirs();//创建多级父目录
        }
        Writer out=new FileWriter(file,true);
        out.write("今天天气真好!");
        out.close();
    }
}

字符输入流:Reader
Reader依然也是一个抽象类。如果要进行文件读取,同样的,使用FileReader。
在上面讲到的Writer类中提供有方法直接向目标源写入字符串,而在Reader类中没有方法可以直接读取字符串类型,这个时候只能通过字符数组进行读取操作。

通过文件读取数据:

package www.bittech;

import java.io.File;
import java.io.Reader;
import java.io.FileReader;


public class Test {
    public static void main(String[] args) throws Exception{
        //// 1.定义文件路径
        File file=new File("E:"+File.separator+"1"+File.separator+"test.txt");
        //// 2.必须保证文件存在才能进行处理
        if(file.exists()){
            Reader in=new FileReader(file);
            char[] date=new char[1024];//每次可读取的最大数量
            int len=in.read(date);// 将数据读取到字符数组中
            String result=new String(date,0,len);
            System.out.println(result);
            in.close();
        }
    }
}

字符流适合处理中文,字节流适合处理一切数据类型(对中文支持不好)。

字节流vs字符流
使用字节流和字符流从代码形式上区别不大。但是如果从实际开发来讲,字节流一定是优先考虑的,只有在处理中文时才会考虑字符流。因为所有的字符都需要通过内存缓冲来进行处理。所有字符流的操作,无论是写入还是输出,数据都先保存在缓存中。如果字符流不关闭,数据就有可能保存在缓存中并没有输出到目标源。这种情况下就必须强制刷新才能够得到完整数据。

字符流刷新操作:

package www.bittech;

import java.io.File;
import java.io.Writer;
import java.io.FileWriter;


public class Test {
    public static void main(String[] args) throws Exception{
        File file=new File("E:"+File.separator+"1"+File.separator+"test.txt");
        if(!file.getParentFile().exists()){//必须保证父目录存在
            file.getParentFile().mkdirs();//创建多级父目录
        }
        Writer out=new FileWriter(file,true);
        out.write("今天天气真好!");
        out.flush();//写上此语句表示强制清空缓冲内容,所有内容都输出
    }
}

在以后进行IO处理的时候,如果处理的是图片、音乐、文字都可以使用字节流,而只有处理中文的时候才会使用字符流。

转换流
字节流和字符流是可以进行相互转换的。
OutputStreamWriter:将字节输出流变为字符输出流(Writer对于文字的输出要比OutputStream方便)
InputStreamReader:将字节输入流变为字符输入流(InputStream读取的是字节,不方便中文的处理)

它们的继承关系以及构造方法:

public class OutputStreamWriter extends Writer
public OutputStreamWriter(OutputStream out)


public class InputStreamReader extends Reader
public InputStreamReader(InputStream in)

实现字节流与字符流的转换:

package www.bittech;

import java.io.*;


public class Test {
    public static void main(String[] args) throws Exception{
        File file=new File("E:"+File.separator+"1"+File.separator+"test.txt");
        if(!file.getParentFile().exists()){//必须保证父目录存在
            file.getParentFile().mkdirs();//创建多级父目录`在这里插入代码片`
        }
        OutputStream output= new FileOutputStream(file);
        Writer out=new OutputStreamWriter(output);//字节流转为字符流
        out.write("今天是你生日吗?");
        out.close();
    }
}

FileOutputStream、FileInputStream、FileWriter、FileReader之间的继承关系:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44149554/article/details/89541771