字节流和字符流

流的概念和作用

是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

字符流和字节流

字符流的由来

因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查指定的码表。

字节流和字符流的区别:
  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
  • 是否使用缓冲区:字符流使用了缓冲区(buffer),而字节流没有使用缓冲区

在字节流中输出数据主要是使用OutputStream完成,输入使用InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成(这四个都是抽象类)。

Java内用Unicode编码存储字符,字符流实际是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成。基于这个特点,处理文本数据一般使用字符流,处理二进制数据(如图片、视频、音频)一般用字节流。

I/O类库的使用

Java中的I/O流类总结图:


字节流和字符流_第1张图片
I/O流类

a. 面向字节的输入输出流

InputStream和OutputStream是所有字节流的基类,是一种抽象类。

InputStream的常用方法:
方法 功能描述
void close() 关闭输入流
int read() 从输入流中当前位置读取一个字节的二进制数据,以此数据为低位字节,补足16位的整型量(0~255)后返回,若输入流中当前位置没有数据,则返回-1
int read(byte b[]) 从输入流当前位置连续读取多个字节并保存到数组中,返回所读取的字节数
int read(byte b[], int offset, int len) 从输入连当前位置连续读取len长的字节,从数组offset位置处开始存放,返回所读取的字节数
int available() 返回输入流中可以读取的字节数
long skip(long n) 跳过字节流中n个字节,此方法有可能失效
boolean markSupported() 判断输入流是否支持标记
void mark(int n) 标记输入流的当前位置, 参数n表示读取n个字节前标记有效
void reset() 将读取位置返回到对此输入流最后调用mark()方法的位置

通过代码验证一下上面的方法:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

/**
 * 字节输入流测试
 * @author Ravior
 *
 */
public class InputStreamTest {

    public static void main(String[] args) {
        
        try {
            InputStream ins = new FileInputStream("data.txt");
            System.out.println("可读取字节长度:"+ins.available());
            int frist = ins.read();
            System.out.println("读取字节:"+frist);
            int second = ins.read();
            System.out.println("读取字节:"+second);
            // 标记输入流当前位置
            if (ins.markSupported()) {
                ins.mark(10);
            } else {
                System.out.println("不支持标记输入流当前位置");
            }
            int three = ins.read();
            System.out.println("读取字节:"+three);
            if (ins.markSupported()) {
                ins.reset();
            } else {
                System.out.println("不支持标记输入流当前位置");
            }
            int four = ins.read();
            System.out.println("读取字节:"+four);
            // 跳过2个字节
            ins.skip(2);
            // 从输入流当前位置读取一个字节
            int five = ins.read();
            System.out.println("读取字节:"+five);
            byte b[] = new byte[2];
            // 从输入流当前位置连续读取字节保存到数组中,并返回读取的字节数
            int readNum = ins.read(b);
            System.out.println("读取的字节数:"+readNum);
            byte b2[] = new byte[2];
            // 从输入流当前位置读取1个字节,从数组1索引位开始存放
            int readNum2 = ins.read(b2, 1, 1);
            System.out.println("读取的字节数:"+readNum2);
            System.out.println("字节数组0:"+b2[0]);
            System.out.println("字节数组1:"+b2[1]);
            // 关闭输入流
            ins.close();
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
OutputStream的常用方法:
方法 功能描述
void close() 关闭输出流
void flush() 强制清空缓存区并向外设输出数据
void write(int b) 将参数b的低位字节写入输出流
void write(byte b[]) 将数组b写入输出流
void write(byte b[], int offset, int len) 将数组b第offset位置开始,写入len个字节到输出流

下面,我们同样用代码验证一下上面的方法:

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


/**
 * Java 字节输出流测试
 * @author Ravior
 *
 */
public class OutputStreamTest {
    
    public static void main(String[] args) {
        try {
            OutputStream os = new FileOutputStream("data.txt");
            // 写入一个字节
            os.write(0);
            os.write(new byte[]{1,0});
            os.write(new byte[]{1}, 0, 1);
            os.flush();
            os.close();
            System.out.println("写入输出流完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件不存在");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("写入文件发生错误");
        }
    }
}

b. 面向字符的输入输出流

字符流是针对字符数据的特点进行过优化的,因而提供一些面向字符的有用特性,字符流的源或目标通常是文本文件。 Reader和Writer是java.io包中所有字符流的父类。由于它们都是抽象类,所以应使用它们的子类来创建实体对象,利用对象来处理相关的读写操作。Reader和Writer的子类又可以分为两大类:一类用来从数据源读入数据或往目的地写出数据(称为节点流),另一类对数据执行某种处理(称为处理流)。

Reader字符输入流

面向字符的输入流类都是Reader的子类,Reader提供的方法和InputStream类似。

方法 功能描述
void close() 关闭输入流
boolean markSupported() 判断当前输入流是否支持mark
void mark() 标记输入流的当前位置
void reset() 将读取位置返回到对此输入流最后调用mark()方法的位置
int read() 从输入流中读取一个字符
int read(char[] ch) 从输入流中读取字符数组
int read(char[] ch, int offset, int len) 从输入连当前位置连续读取len长的字节,从数组offset位置处开始存放,返回所读取的字节数
boolean ready() 判断流是否可以读取
long skip(long n) 跳过流内的n个字符

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