Java之IO流

File类:

File类的构造方法:

  • File(File parent, String child)
    通过父级路径file对象+子路径String创建file对象
  • File(String pathname)
    通过路径String创建file对象
  • File(String parent, String child)
    通过父级路径String+子路径String创建file对象
  • File(URI uri)
    通过file:uri创建file对象
    uri:统一资源标识符,用来唯一标识某个资源
    url:统一资源定位符,uri的一个子类,实现定位的uri

常用方法:

  • boolean createNewFile()
    当文件不存在时,创建该文件
  • boolean mkdir()
    创建目录,该方法在父级路径存在时才会创建成功
  • boolean mkdirs()
    创建目录,该方法在父级目录不存在时,也会创建父级目录
  • boolean delete()
    删除文件或目录
  • boolean exists()
    判断file是否存在
  • boolean isAbsolute()
    判断是否是绝对路径
  • boolean isDirectory()
    判断是否是目录
  • boolean isFile()
    判断是否是文件
  • File getAbsoluteFile()
    获得file的绝对路径,以File对象形式返回
  • String getAbsolutePath()
    获得file的绝对路径,以字符串形式返回
  • String getName()
    获得文件或目录名
  • String getParent()
    获得父级目录的路径
  • File getParentFile()
    获得父级目录的路径
  • String getPath()
    file路径转换为字符串形式
  • String[] list()
    以字符串形式返回file路径下的文件和目录
  • File[] listFiles()
    以file形式返回file路径下的文件和目录
  • boolean renameTo(File dest)
    重命名

遍历文件

	/**
     * 获得该目录下的所有文件及子文件
     *
     * @param path
     * @return
     */
    public static void getAllFile(String path) {
        File root = new File(path);
        if(!root.exists()){
            return;
        }
        File[] files = root.listFiles();
        for (File file : files){
            if(file.isDirectory()){//如果是目录,则继续遍历
                getAllFile(file.getAbsolutePath());
            }else {
                System.out.println(file.getAbsolutePath());
            }
        }
    }

Java的IO架构

I即Input,外部程序向Java程序传递数据
O即Output,Java程序向外部程序传递数据
这里是IO流的大致框架,网上抠的

分类

  • 按照传输方向:输入流和输出流
  • 按照传输内容:字节流和字符流

字节流和字符流有啥区别呢?

来个单位换算:
1字符(char)= 2字节(byte)=16位(bit)
字节流可以处理任意类型的数据,当使用字节流读取中文文件时,每次读的可能不是一个完整的字符,这时候,程序就不认识那半个字符,所以就容易出现乱码。而字符流则是按照字符读取。但是当读取像图片、视频等等的文件,字符流就用不上了。

字节流

InputStream:字节输入流的父类接口
OutputStream:字节输出流的父类接口

常用方法

OutputStream:

  • void write(byte[] b)
    将数组写入到输出流
  • void write(byte[] b, int off, int len)
    将数组从off位置,写入len个长度到输出流
  • void write(int b)
    将指定字节写入输出流,b会强转成byte类型
  • void close()
    关闭流

InputStream:

  • int read()
    从输入流读取数据的下一个字节
  • int read(byte[] b)
    从输入流读取字节,并存储到b
  • int read(byte[] b, int off, int len)
    从输入流off位置,读取len个字节,并存储到b
  • void close()
    关闭流

对文件写入和读取

	public static void main(String[] args) throws IOException {
    InputStream is = null;
    OutputStream os = null;
    File file = new File("H://a.txt");
    is = new FileInputStream(file);
    os = new FileOutputStream(file, true);//追加模式,默认为覆盖
    byte[] bytesWrite = "我是Java界的小学生".getBytes();
    os.write(bytesWrite);
    os.close();//用完就关闭
    int len = 0;
    byte[] bytesRead = new byte[1024];
    while ((len = is.read(bytesRead)) != -1) {//读完返回-1
        System.out.println(new String(bytesRead,0,len));
    }
    is.close();
}

字符流

Reader:字符输入流父类接口
Writer:字符输出流父类接口

常用方法

Writer

  • Writer append(char c)
    链式编程,将字符写入该字符输出流,并返回该输出流
  • void write(int c)
    将字符写入该字符输出流
  • void write(char[] cbuf)
    将字符数组写入该字符输出流
  • void write(String str)
    将字符串写入该字符输出流
  • void write(String str, int off, int len)
    将该字符串,从off开始,写len个长度到该字符输出流
  • void flush()
    刷新流,将缓冲区的字符写入文件,当close()时会调用,也可以通过该方法强制刷新

Reader

  • int read()
    读取一个字符
  • int read(char[] cbuf)
    将字符读入数组
  • int read(char[] cbuf, int off, int len)
    将字符从off读取len个长度到数组

使用字符流重写上面的程序

	public static void main(String[] args) throws IOException {
        Reader is = null;
        Writer os = null;
        File file = new File("H://a.txt");

        is = new FileReader(file);
        os = new FileWriter(file, true);//追加模式,默认为覆盖
        String w = "我是Java界的小学生";
        os.write(w);
        os.flush();//不关闭时,必须刷新
        os.close();//关闭自动刷新
        int len = 0;
        char[] r = new char[1024];
        while ((len = is.read(r)) != -1) {//读完返回-1
            System.out.println(new String(r,0,len));
        }
        is.close();
    }

转换流

用于将字节流转换为字符流
InputStreamReader:将字节输入流转换为字符输入流
OutputStreamWriter:将字节输出流转换为字符输出流

将字节流转换为字符流后写入读取文件

public static void main(String[] args) throws IOException {
    InputStream is = null;
    OutputStream os = null;
    File file = new File("H://a.txt");
    is = new FileInputStream(file);
    os = new FileOutputStream(file, true);//追加模式,默认为覆盖
    //字节转字符
    InputStreamReader inputStreamReader = new InputStreamReader(is, "utf-8");//指定字符集
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os, "utf-8");
    String w = "我是Java界的小学生";
    outputStreamWriter.write(w);
    outputStreamWriter.flush();//不关闭时,必须刷新
    outputStreamWriter.close();//关闭自动刷新
    int len = 0;
    char[] r = new char[1024];
    while ((len = inputStreamReader.read(r)) != -1) {//读完返回-1
        System.out.println(new String(r,0,len));
    }
    is.close();
}

缓冲流

当对文件频繁操作时,性能和效率低。缓冲流就是将数据先缓存起来,然后一起写入或读取,可以提高文件操作的效率。
缓冲流分为字节缓冲流和字符缓冲流

字节缓冲流

public static void main(String[] args) {
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try{
        bis = new BufferedInputStream(new FileInputStream("H://a.txt"));
        bos = new BufferedOutputStream(new FileOutputStream("H://a.txt"));
        bos.write("我是Java界的小学生".getBytes());
        bos.flush();
        byte[] c = new byte[1024];
        int len = 0;
        while ((len = bis.read(c))!= -1){
            System.out.println(new String(c,0,len));
        }
    }catch (Exception e){
        e.printStackTrace();
    } finally {
        try {
            bis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符缓冲流

public static void main(String[] args) {
    BufferedReader bis = null;
    BufferedWriter bos = null;
    try{
        bis = new BufferedReader(new FileReader("H://a.txt"));
        bos = new BufferedWriter(new FileWriter("H://a.txt"));
        bos.write("我是Java界的小学生");
        bos.flush();
        char[] c = new char[1024];
        int len = 0;
        while ((len = bis.read(c))!= -1){
            System.out.println(new String(c,0,len));
        }
    }catch (Exception e){
        e.printStackTrace();
    } finally {
        try {
            bis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

序列化

ObjectInputStream&ObjectOutputStream

使用DataOutputStream可以将对象存入文件
使用DataInputStream可以取出该对象
使用他们的前提是,该对象及其属性都实现了序列化
首先构建一个实现了序列化的类

class Stu implements Serializable{
    String name;
    String clazz;
    int age;
    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", clazz='" + clazz + '\'' +
                ", age=" + age +
                '}';
    }
}

然后将该对象存入文件

public static void main(String[] args) {
        ObjectInputStream is = null;
        ObjectOutputStream os = null;
        FileOutputStream fileOutputStream = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("H://a.txt");
            fileOutputStream = new FileOutputStream("H://a.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            os = new ObjectOutputStream(fileOutputStream);
            is = new ObjectInputStream(fileInputStream);
            Stu s = new Stu();
            s.age = 18;
            s.clazz = "1年级1班";
            s.name = "荼蘼";//超级留级生
            os.writeObject(s);
            os.flush();

            Stu o = (Stu) is.readObject();
            System.out.println(o);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
Stu{name='荼蘼', clazz='1年级1班', age=18}

容易产生的问题

java.io.EOFException
	at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2638)
	at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3113)
	at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:853)
	at java.io.ObjectInputStream.<init>(ObjectInputStream.java:349)
	at com.dmlll.objects.Test.main(Test.java:19)

当新建一个文件存储ObjectOutputStream文件时,如果把ObjectInputStream放在ObjectOutputStream之前声明,则会报这个错误
读源码得知:
在这里插入图片描述

局部序列化

  1. transient
    修改Stu
class Stu implements Serializable {
    transient String name;
    String clazz;
    int age;
    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", clazz='" + clazz + '\'' +
                ", age=" + age +
                '}';
    }
}

main方法不变
输出结果

Stu{name='null', clazz='1年级1班', age=18}
  1. static
    修改Stu
class Stu implements Serializable {
    static String name;
    String clazz;
    int age;
    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", clazz='" + clazz + '\'' +
                ", age=" + age +
                '}';
    }
}

读取前将name设置为“小明”

Stu{name='小明', clazz='1年级1班', age=18}

在没有拿到序列化后的对象时,值可以被改变,说明name没有被序列化
3.实现Externalizable,重写writeExternal和readExternal
该类实际就是继承了Serializable接口,抽象出了这两个方法。
实现Serializable接口,重写这两个方法也可以
Java会调用ObjectOutputStream类检查Stu是否有私有的、无返回值的writeObject方法,如果有,Stu会委托该方法进行对象序列化。

修改Stu

class Stu implements Externalizable {
    String name;
    String clazz;
    int age;

    public Stu() {
    }

    @Override
    public String toString() {
        return "Stu{" +
                "name='" + name + '\'' +
                ", clazz='" + clazz + '\'' +
                ", age=" + age +
                '}';
    }

    public Stu(String name, String clazz, int age) {//必须要有构造器
        this.name = name;
        this.clazz = clazz;
        this.age = age;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(clazz);
        out.writeObject(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        clazz = (String) in.readObject();
        age = (int)in.readObject();
    }
}

结果

Stu{name='null', clazz='1年级1班', age=18}

异常处理中流的关闭

1.7可以这么关

public static void main(String[] args) {
        try (FileOutputStream fileOutputStream = new FileOutputStream("H://a.txt");
             FileInputStream fileInputStream = new FileInputStream("H://a.txt");
        ObjectOutputStream os = new ObjectOutputStream(fileOutputStream);
            ObjectInputStream is = new ObjectInputStream(fileInputStream)){
            Stu s = new Stu();
            s.age = 18;
            s.clazz = "1年级1班";
            s.name = "荼蘼";//超级留级生
            os.writeObject(s);
            os.flush();
            s.name = "小明";
            Stu o = (Stu) is.readObject();
            System.out.println(o);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

但是如果有多个try块也挺麻烦的
java9可以这么搞

public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("H://a.txt");
        FileInputStream fileInputStream = new FileInputStream("H://a.txt");
        ObjectOutputStream os = new ObjectOutputStream(fileOutputStream);
        ObjectInputStream is = new ObjectInputStream(fileInputStream);
        try (fileOutputStream;fileInputStream;os;is){
            Stu s = new Stu();
            s.age = 18;
            s.clazz = "1年级1班";
            s.name = "荼蘼";//超级留级生
            os.writeObject(s);
            os.flush();
            s.name = "小明";
            Stu o = (Stu) is.readObject();
            System.out.println(o);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值