美文网首页
字节流和字符流

字节流和字符流

作者: 今有所思 | 来源:发表于2016-10-21 09:27 被阅读666次

    流的概念和作用

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

    字符流和字节流

    字符流的由来

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

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

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

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

    I/O类库的使用

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


    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个字符

    相关文章

      网友评论

          本文标题:字节流和字符流

          本文链接:https://www.haomeiwen.com/subject/nxwquttx.html