字节流和字符流

File类虽然可以操作文件,但是并不是操作文件的内容,如果要进行内容的操作只能通过两种途径:字节流、字符流

如果要进行输入,输出操作一般都会按照如下的步骤(以文件操作为例):

  • 通过File类定义一个要操作文件的路径;
  • 通过字节流或字符流的子类对象为父类对象实例化;
  • 进行数据的读(输入)、写(输出)操作;
  • 数据流属于资源操作,资源操作必须关闭。

java.io包定义了两类流:

  • 字节流(JDK 1.0) : InputStream、OutputStream;
  • 字符流(JDK 1.1) : Reader、Writer。

1 字节输出流:OutputStream(重点)

OutputStream类是一个专门进行字节数据输出的一个类,定义如下:

public abstract class OutputStream
extends Object
implements Closeable, Flushable

可以发先OutputStream类实现了个两个接口:Closeable, Flushable;这两个接口定义如下:

Closeable接口(JDK 1.5) Flushable接口(JDK 1.5)
public interface Closeable extends AutoCloseable public interface Flushable

在JDK 1.7 中引入了自动关闭机制,所以Closeable又继承AutoCloseable接口,定义如下:

public interface AutoCloseable {
    public void close() throws Exception;
}

但是OutputStream类在JDK 1.0的时候就提供了,这个类原本就定义了close()和flush()两个方法,所以现在以上的两个接口就几乎可以忽略。
在OutputStream类里面提供有三个输出的方法:

  • 输出单个字节:public abstract void write(int b) throws IOException
  • 输出全部字节数组:public void write(byte[] b) throws IOException
  • 输出部分字节数据public void write(byte[] b, int off, int len) throws IOException
    OutputStream是抽象类,如果为抽象类进行实例化操作,那么必须使用抽象类的子类,由于要使用文件操作,可以使用FileOutputStream子类,这个子类里面定义如下的构造方法:
  • 创建或覆盖已有文件:public FileOutputStream(File file) throws FileNotFoundException
  • 文件内容追加:public FileOutputStream(File file, boolean append) throws FileNotFoundException

范例:文件内容的输出

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

public class IntOrOutPutStream {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "Document" + File.separator + "test.txt");
        if (!file.getParentFile().exists()) {
            file.mkdirs();
        }
        
        OutputStream output = new FileOutputStream(file);
        
        String str = "好好学习,天天向上!";
        byte[] data = str.getBytes();
        output.write(data);
        output.close();
    }
}

以上是整个字节数组的内容进行了输出,如果此时要输出的文件不存在,就会自动创建文件。
范例:单个字节的方式输出

        for (int x = 0 ; x < data.length ; x++) {
            output.write(data[x]);
        }

范例:输出部分字节数组内容

output.write(data, 6, 4);

以上都是直接覆盖原有文件内容,也可以实现内容的追加,只需要更换FileOutputStream类的构造方法即可:

OutputStream output = new FileOutputStream(file , true);
//  \r\n 可以实现换行
String str = "好好学习,天天向上!\r\n";

2 字节输入流:InputStream

如果需要进行数据的读取操作,可以利用InputStream类实现功能,此类定义:public abstract class InputStream extends Object implements Closeable
虽然此类实现了Closeable接口,但是与OutputStream类一样,可以不用考虑接口的存在,在InputStream类里面也定义又数据读取的方法:

  • 读取单个字节:public abstract int read() throws IOException
    · 返回值:返回读取的字节内容,如果结尾没有数据了,返回 -1
  • 将读取的数据保存在里字节数组里:public int read(byte[] b) throws IOException
    · 返回值:返回读取的数据长度,如果已经读取到结尾,返回 -1
  • 将读取的数据保存在部分字节数据里:public int read(byte[] b, int off, int len) throws IOException
    · 返回值:读取的部分数据的长度,如果已经读取到结尾,返回 -1

InputStream是一个抽象类,如果要进行文件读取使用子类FileInputStream,此子类的构造方法:public FileInputStream(File file) throws FileNotFoundException
范例:向数组里面读取数据

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class InputStreamTest {
    public static void main(String[] args) throws Exception{
        //1.定义要输入的文件路径
        File file = new File("D:" + File.separator + "Document" + File.separator + "test.txt");
        if (file.getParentFile().exists()) {
            //2. 使用InputStream进行读取
            InputStream input = new FileInputStream(file);
            //3. 读取数据
            byte[] data = new byte[1024];   //准备长度为1024的数组
            int len = input.read(data);     //将内容保存到字节数组中
            //4. 关闭输入流
            input.close();
            System.out.println("{" + new String(data , 0 ,len) + "}");
        }
        
    }
}

范例:单个字节数据读取

  • 文件有很多字节数据,所以读取数据应采用循环的方式,但由于不确定循环次数,所以使用while循环。
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;

public class InputStreamWhileTest {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "Document" + File.separator + "test.txt");
        if (file.getParentFile().exists()) {
            InputStream input = new FileInputStream(file);
            byte[] data = new byte[1024];
            int temp = 0;
            int foot = 0;
            //temp = input.read() , 表示将read() 方法读取的字节内容赋值给temp变量
            //(temp = input.read()) != -1 , 判断读取temp的内容是否是-1
            while ((temp = input.read()) != -1) {
                data[foot++] = (byte) temp;     //有内容进行保存
            }
            input.close();
            System.out.println("{" +new String(data , 0 , foot)+ "}");
        }
    }
}

3 字符输出流:Writer

Writer类是在JDK1.1之后增加的,其类的定义如下:
public abstract class Writer extends Object implements Appendable, Closeable, Flushable
这个类除了实现了Closeable与Flushable接口外,又多实现了一个Appendable,这个接口的定义如下:

public interface Appendable {
  public Appendable append(char c) throws IOException {}
  public Appendable append(CharSequence csq) throws IOException {}
  public Appendable append(CharSequence csq, int start, int end) throws IOException {}
}

在Appendable接口里面定义了追加类的操作,而且追加的数据都是字符或者字符串。
在Writer类里面定义有一下的输出方法(部分):

  • 输出全部字符数组:public void write(char[] cbuf) throws IOException
  • 输出字符串:public void write(String str) throws IOException
    Writer是一个抽象类,如果想要为这个类的对象实例化,应该使用FileWriter子类:
    范例:使用Writer类实现内容输出
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class WriterTest {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "Document" 
                + File.separator + "Document" + File.separator + "test.txt");
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        
        Writer writerfile = new FileWriter(file);
        String str = "Hello world!";
        writerfile.write(str);
        writerfile.close();
    }
}

4 字符输入流:Reader

Reader 是进行字符数据读取的输入流,其本身也是一个抽象类:
public abstract class Reader extends Object implements Readable, Closeable
在Reader类里面也提供有一系列的read()方法:

  • 读取内容到字符数组:public int read(char[] cbuf) throws IOException
    · 返回值:表示读取的数据长度,如果已经读取到结尾了,返回 -1;
    为Reader类实例化的可以使用FileReader子类完成。
    范例:使用Reader读取数据
import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class ReaderTest {
    public static void main(String[] args) throws Exception {
        File file = new File(
                "D:" + File.separator + "Document" + File.separator + "Document" + File.separator + "test.txt");
        if (file.getParentFile().exists()) {
            Reader readerfile = new FileReader(file);
            char[] data = new char[1024];
            int len = readerfile.read(data);
            readerfile.close();
            System.out.println(new String(data, 0, len));
        }
    }
}

5 字节流与字符流的区别?

  1. 字节流直接与终端进行数据交互,字符流需要将数据经过缓冲去处理后才可以输出。
  2. 在使用OutputStream输出数据的时候,即使最后没有关闭输出流,内容也可以正常输出,但是不关闭字符输出流,就表示在缓冲区中处理的内容不会被强制性清空,所以就不会输出数据;如果有特殊情况不能够关闭字符输出流,可以使用flush()方法强制清空缓冲区。
    范例:强制清空缓冲区
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class FlushTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:" + File.separator + "Document" + File.separator + "Document" + File.separator + "test.txt");
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        Writer out = new FileWriter(file);
        String str = "Hello world @!";
        out.write(str);
        out.flush();
    }
}

在开发之中,对字节数据处理是比较多的,例如:图片、音乐、电影;而对字符流最大的好处就是可以处理中文,所以在日后的开发之中,如果要处理中文, 优先考虑字符流,没有中文时,建议使用字节流。

你可能感兴趣的:(字节流和字符流)