Java SE(十七):FIS、FOS、BIS和BOS、IO流、字符流


Java SE

例。


一、FIS

FIS(构造、异常、close)

FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定

FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定

IOException
当发生某种I/O异常时,抛出此异常。此类为异常的通用类,它是由失败的或中断的I/O操作生成的

close方法
关闭此输入流并释放与该流关联的所有系统资源

FIS(read)

方法 功能
int read() 读取一个byte无符号填充到int低八位
int read(byte[] b) 从此输入流中将最多b.length个字节的数据读入一个字节数组中,返回读取的字节的个数
int read(byte[] b,int off,int len) 从此输入流中将最多len个字节的数据读入一个字节数组中
import java.io.FileInputStream;
import java.io.IOException;

/**
 * java.io.FileInputStream
 * 文件输入流,是一个低级流,用于从文件中读取字节
 */
public class FISDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileInputStream file = new FileInputStream("fos.txt");
        byte[] data = new byte[100]; //创建一个100长度字节的数组
        int len = file.read(data); //读取file文件中一百个字节数据
        String str = new String(data,0,len,"UTF-8"); //从指针0位置按UTF-8格式读取len长度字节
        System.out.println(str);
        file.close();
    }
}

代码案例:使用文件流来复制文件

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 使用文件流复制文件
 */
public class CopyDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        /*
        使用文件输入流读取原文件,再使用文件输出流向目标文件中写入
        顺序从原文件中读取每个字节并写入到目标文件即可完成复制
         */
        FileInputStream src = new FileInputStream("image.png");
        FileOutputStream desc = new FileOutputStream("image02.png");
        int d = -1; //默认在文件末尾,只是赋初值,具体值赋几都行
        byte[] data = new byte[100];
        long start = System.currentTimeMillis();
        while((d=src.read(data))!=-1){
    
    
            desc.write(data,0,d); //每次最多写data个字节,从指针0可是写d个字节
        }
        long end = System.currentTimeMillis();
        System.out.println("复制完毕!耗时:"+(end-start)+"ms");
        src.close();
        desc.close();
    }
}

二、FOS

FOS(构造)

方法 功能
FileOutputStream(File file) 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file,boolean append) 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(String name,boolean append) 创建一个向具有指定name的文件中写入数据的输出文件流

FOS(write)

方法 功能
void write(byte[] b) 将b.length个字节从指定字节数组写入此文件输出流中
void write(byte[] b,int off,int len) 将指定字节数组中从偏移量off开始的len个字节写入此文件输出流
void write(int b) 将指定字节写入此文件输出流
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 流
 * 流根据方向的不同分为输入流和输出流,参照点为当前程序
 * 输入流用来读取数据,输出流用来写出数据
 * java.io.InputStream抽象类,定义了输入流的读取字节方法,所有的字节输入流都继承自它
 * java.io.OutputStream则是所有字节输出流的父类
 *
 * 流分为节点流与处理流
 * 节点流,也叫低级流,是负责读写数据的流,读写操作中必须要有低级流,数据源明确
 * 处理流,也叫高级流,读写可以没有高级流,高级流也不能独立存在,必须用于处理其他流,处理其他流的目的是简化读写数据中的操作
 *
 * java.io.FileOutputStream
 * 文件输出流,是一个低级流,作用是向文件中写出字节
 */
public class FOSDemo  {
    
    
    public static void main(String[] args) throws IOException {
    
    
        /*
        默认创建的FOS是覆盖写操作
        FOS会将文件数据(若有数据)全部删除,然后在开始写
         */
        FileOutputStream fos = new FileOutputStream("fos.txt");
        String str = "我喜欢Java!";
        /*
        String->byte[]

        byte getBytes()
        将当前字符串按照系统默认字符集转换为一组字节

        byte getBytes(String csn)
        按照给定的字符集将当前字符串转换为一组字节
         */
        byte[] date = str.getBytes("UTF-8");
        fos.write(date);
        System.out.println("写出完毕!");
        fos.close();
    }
}
import java.io.FileOutputStream;
import java.io.IOException;

/*
文件输出流,追加写操作
 */
public class FOSDemo1 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        /*
        在创建FOS时,若指定第二个参数,并且该值为true时,则是追加写操作,那么本次通过FOS写出的内容会被追加到该文件末尾
         */
        FileOutputStream fos = new FileOutputStream("fos.txt",true);
        fos.write("不可能!".getBytes("UTF-8"));
        System.out.println("写出完毕!");
        fos.close();
    }
}

三、BIS和BOS

1、节点流和过滤流

**节点流:**从特定的地方读写的流类,例如:磁盘或一块内存区域

**过滤流:**使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流连接创建的
FileInputStream和FileOutputStream,字节流,用于从文件中读取或往文件中写入字节流。如果在构造FileOutputStream时,文件已存在,则覆盖这个文件

**BufferedInputStream和BufferedOutputStream:**过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率

**DataInputStream和DataOutputStream:**过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能

**PipedInputStream和PipedOutputStream:**管道流,用于线程间的通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有用,必须同时构造管道输入流和管道输出流

BOS基本原理

BufferedOutputStream为IO操作提供了缓冲区,写入操作时,加上缓冲流,这种流模式是为了提高IO(输出)的性能
例我们想从应用程序中把数据放入文件,相当于将一缸水倒入另一个缸中:
(1)、仅使用FOS的write()方法,相当于一滴水一滴水的“转移”
(2)、使用BOS的writeXxx()方法更方便,相当于从DOS一瓢一瓢放入桶(BOS)中,再从桶(BOS)中倒入另一个缸,性能提高了

import java.io.*;

/**
 * 缓冲输出流写出数据的缓冲区域问题
 */
public class BOSDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileOutputStream fos = new FileOutputStream("bos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bos.write("呵呵哒".getBytes("UTF-8")); //将写入内容放在缓冲区中,当缓冲区放满后,一次性写入到bos中
        bos.flush(); //强制将缓冲区中的字节一次性写出
        System.out.println("写出结束!");
        bos.close();
    }
}

BIS基本原理

BufferedInputStream是一个带有缓冲区的输入流,通常使用它可以提高我们的读取效率

(1)、每次调用read方法的时候,它首先尝试从缓冲区里读取数据

(2)、若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中

(4)、最后再将缓冲区中的内容部分或全部返回给用户。由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快,所以BufferedInputStream的效率很高

import java.io.*;

/**
 *
 * 缓冲流
 * java.io.BufferedInputStream
 * java.io.BufferedOutputStream
 * 缓冲字节输入输出流是一对高级流,使用它们可以加快读写效率
 * 高级流可以处理其他流,但是无论添加了多少高级流,最底下都要有低级流,因为低级流是真实读写数据的流
 * 高级流都是处理数据的,高级流处理其他流就形成了流的链接,并且有效的组合不同的高级流可以得到叠加的效果
 */
public class CopyDemo1 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileInputStream fis = new FileInputStream("image.png");
        FileOutputStream fos = new FileOutputStream("image03.png");
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int d = -1;
        long start = System.currentTimeMillis();
        /*
        缓冲流内部有一个缓冲区当bis.read方法读取第一个字节时,实际上BIS会一次性读取一组字节并存入内部的字节数组中
        然后将第一个字节返回,当再次调用read方法时,BIS直接从字节数组中将第二个字节返回
        直到字节数组中所有字节全部返回后,才会再次读取一组字节
        所以缓冲流也是依靠提高一次读写的数据量减少读写次数来达到提高读写效率的
         */
        while((d=bis.read())!=-1){
    
    
            bos.write(d);
        }
        long end = System.currentTimeMillis();
        System.out.println("复制完毕!耗时:"+(end-start)+"ms");
        bis.close();
        bos.close();
    }
}

四、IO流应用

对象序列化的基本原理

将Object转换为byte序列,就是序列化,反之叫反序列化
为了在byte流中存储对象
使用writeObject(Object)/readObject()进行序列化和反序列化

Serializalbe接口

Serializalbe是序列化接口,对象必须实现“序列化接口”才能进行“序列化”否则出现不能序列化的异常
JavaBean规范,必须实现Serializable接口Java API中的类大多是Java Bean,基本都实现了Serializable

transient关键字

transient是Java语音的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的表示中,然而非transient型的变量是被包括进去的
Transient修饰的属性可以通过其它手段进行序列化,可以参考ArrayList源码,ArrayList中底层数据组是用transient修饰,但进行了序列化

OOS和OIS

import java.io.Serializable;
import java.util.List;

/**
 * 该类用于测试作为对象流读写对象使用
 *
 * 当一个类需要被对象流读写,那么该类必须实现java.io.Serializable接口
 */
public class Person implements Serializable {
    
    
    /**
     *当一个类实现了Serializable接口后应当添加一个常量:serialVersionUID
     * 该常量为当前类的序列化版本号,若不定义系统会根据当前类的机构生成,但是只要类的机构发生改变,版本号也会相应发生改变
     *
     * 版本号影响反序列化的结果,即:当OIS对一个对象进行反序列化时,会检查该对象与类的版本是否一致:
     * 若一致:反序列化成功,但是若该对象与类的机构不一致时,则采用兼容模式,能还原的属性都还原
     * 若不一致:反序列化直接抛出版本不一致异常
     */
    private static final long serialVersionUID = 1l;
    private String name;
    private int age;
    private String gender;
    /*
    transient关键字用来修饰属性
    当被修饰后,该类实例在使用OOS进行对象序列化时,该属性值被忽略,从而达到对象“瘦身”的mud
     */
    private transient List<String> otherInfo;

    public Person(){
    
    

    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public void setGender(String gender) {
    
    
        this.gender = gender;
    }

    public void setOtherInfo(List<String> otherInfo) {
    
    
        this.otherInfo = otherInfo;
    }

    public String getName() {
    
    
        return name;
    }

    public int getAge() {
    
    
        return age;
    }

    public List<String> getOtherInfo() {
    
    
        return otherInfo;
    }

    public String getGender() {
    
    
        return gender;
    }

    public Person(String name, int age, String gender, List<String> otherInfo){
    
    
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.otherInfo = otherInfo;
    }

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", otherInfo=" + otherInfo +
                '}';
    }

    //public String toString(){
    
    
    //    return name+","+age+","+gender+","+otherInfo;
    //}
}

ObjectOutputStream writeObject(Object)序列化对象

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 对象流
 * 对象流是一对高级流,作用是方便读写java中的对象
 * java.io.ObjectOutputStream
 * 对象输出流,可以将给定的对象转换为一组字节后写出
 */
public class OOSDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        Person p = new Person();
        p.setName("刘老师");
        p.setAge(20);
        p.setGender("男");
        List<String> otherInfo = new ArrayList<String>();
        otherInfo.add("是一位员工");
        otherInfo.add("测试员工");
        otherInfo.add("很优秀");
        p.setOtherInfo(otherInfo);

        FileOutputStream fos = new FileOutputStream("person.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        /*
        ObjectOutputStream的writeObject方法可以将给定对象转换为一组字节后写出
        这些字节比该对象实际内容要大,因为除了数据外还有结构等描述信息

        下面的代码实际上经历了两个操作:
        1:oos将Person对象转换为一组字节将一个对象转换为一组字节的过程称为:对象序列化
        2:再通过fos将这组字节写入到硬盘将该对象转换的字节写入到硬盘做长久保存的过程称为:对象持久化
         */
        oos.writeObject(p);
        System.out.println("写出对象完毕!");
        oos.close();
    }
}

ObjectInputStream readObject()对象的反序列化

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * java.io.ObjectInputStream
 * 对象输入流,作用是可以进行对象反序列化,读取一组字节并还原为对象
 * OIS读取的字节必须是由OOS将对象序列化得到的字节,否则会抛出异常
 */
public class OISDemo {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        FileInputStream fis = new FileInputStream("person.obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //对象反序列化
        Person p = (Person) ois.readObject();
        System.out.println(p);
        ois.close();
    }
}

五、字符流

ISR和OSW概述

字符的处理,一次处理一个字符(unicode)

字符的底层仍然是基本的字节流

字符流的基本实现:InputStreamReader完成byte流解析为char流,按照编码解析;OutputStreamWriter提供char流到byte流,按照编码处理

import java.io.*;

/**
 * java.io.InputStreamReader
 * 字符输入流,可以按照给定的字符集读取字符
 */
public class ISRDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileInputStream fis = new FileInputStream("osw.txt"); //字节流
        InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
        int d = -1;
        while((d = isr.read())!=-1){
    
    
            System.out.print((char)d);
        }
        isr.close();
    }
}
import java.io.*;

/**
 * 字符流
 * 字符流的读写单位为字符
 * 字符流都是高级流,虽然以字符为单位读写数据,但实际底层还是读写字节,只是从字节与字符的转换工作交给了字符流来完成
 * java.io.Reader:字符输入流的顶级父类
 * java.io.Writer:字符输出流的顶级父类
 *
 * 转换流
 * java.io.OutputStreamWriter
 * 特点是可以按照指定的字符集写出字符
 *
 * 之所以称OutputStreamWriter与InputStreamReader为转换流,是因为大多数的字符流都只处理其他字符流
 * 而低级流又是字节流,这就导致字符流不能处理字节流的问题
 * 转换流相当于一个转换器的作用,它们可以将字节流转变为字符流,这样其他的字符流就可以处理了
 */
public class OSWDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileOutputStream fos = new FileOutputStream("osw.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
        osw.write("我喜欢学习java。");
        osw.write("那是不可能的!");
        System.out.println("写出完毕!");
        osw.close();
    }
}

BR和BW

字符流的过滤器是字符读写的功能扩展,极大的方便了文本的读写操作

import java.io.*;

/**
 * java.io.BufferedReader
 * 缓冲字符输入流,特点:按行读取字符串
 */
public class BRDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        FileInputStream fis = new FileInputStream("src/day08/BRDemo.java"); //读取BRDemo.java
        InputStreamReader isr = new InputStreamReader(fis);
        BufferedReader br = new BufferedReader(isr);
        /*
        BufferedReader提供了按行读取方法:
        String readLine()
        连续读取若干字符,直到读取到换行符为止,并将换行符之间读取的字符以一个字符串返回
        若返回值为NULL,则表示读取到末尾
        注意:该字符串不包含最后的换行符
         */
        String line = null;
        while((line = br.readLine())!=null){
    
    
            System.out.println(line);
        }
        br.read();
    }
}

装饰模式简介

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活

六、Reader和Writer

字符流原理

Reader是字符输入流的父类

Writer是字符输出流的父类

字符流是以字符(char)为单位读写数据的,一次处理一个unicode

字符流的底层依然是基本的字节流

常用方法

Reader的常用方法:

int read():读取一个字符,返回的int值“低16”位有效
int read(char[] chs):从该流中读取一个字符数组的length个字符并存入该数组,返回值为实际读取到的字符量

Writer的常用方法:

void write(int c):写出一个字符,写出给定int值“低16”位表示的字符
void write(char[] chs):将给定字符数组中所有字符写出
void write(String str):将给定的字符串写出
void write(char[] chs,int offset,int len):将给定的字符数组中从offset处开始连续的len个字符写出

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

/**
 * 缓冲字符流
 * BufferedWrite,BufferedReader
 * 特点是可以按行读写字符串
 *
 * java.io.PrintWriter
 * 具有自动行刷新的缓冲字符输出流
 * 创建PrintWriter时,它一定会在内部创建BufferedWriter作为缓冲功能的叠加
 */
public class PWDemo {
    
    
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    
    
        /*
        提供了多种构造方法
        其中有两个可以直接对文件进行写出操作的构造方法:
        PrintWriter(File file)
        PrintWriter(String path)
         */
        PrintWriter pw = new PrintWriter("pw.txt","UTF-8");
        pw.println("学习java!");
        pw.println("学习Python!");
        System.out.println("写出完毕!");
        pw.close();
    }
}

字符转换流原理

InputStreamReader:字符输入流
使用该流可以设置字符集,并按照指定的字符集从流中按照该编码将字节数据转换为字符并读取
OutoutStreamWriter:字符输出流
使用该流可以设置字符集,并按照指定的字符集将字符转换为对应字节后通过该流写出

import java.io.*;

/**
 * PrintWriter也提供了可以处理其他流的构造方法
 * 提供的方法可以传入字节流,也可以处理字符流,并且,当使用这类构造方法时,可以再传入第二个参数
 * 该参数为boolean值,该值为true时,则具有了自动行刷新功能
 */
public class PWDemo2 {
    
    
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    
    
        FileOutputStream fos = new FileOutputStream("pw1.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8"); //使用字符流指定编码级
        PrintWriter pw = new PrintWriter(osw);
        pw.println("星期一!");
        pw.println("星期二!");
        System.out.println("写出完毕!");
        pw.close();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45138120/article/details/125287106
今日推荐