Java - IO

41

介绍:

Input Output Stream

狭义: 数据在内存中输入和输出, 本地进程间的数据流动

广义: 不同电脑之间的数据流动, 远程进程间的数据流动

流的流动方式(数据的传输方向) :

  • 输入流
  • 输出流

流的数据格式:

  • 字节流
  • 字符流

File对象:

Java封装的一个操作文件及文件夹的对象

返回值方法描述
File(String pathname)构造方法
File(String parent, String child)构造方法
File(File parent, String child)构造方法
File(URI uri)构造方法, 用于网络
booleancreateNewFile() throws IOException创建文件, 已存在就返回 false, 不存在就新建, 需要处理异常
booleanexists()是否存在
booleancanExecute()是否有执行权限
booleancanWrite()是否有写权限
booleancanRead()是否有读权限
booleandelete()删除文件
voiddeleteOnExit()在JVM退出时删除文件
FilegetAbsoluteFile()返回绝对路径对象
StringgetAbsolutePath()返回绝对路径
longgetFreeSpace()空闲空间
longgetUsableSpace()可用空间
longgetTotalSpace()总空间
longlength()返回文件大小
StringgetName()获取文件名
StringgetParent()获取父级路径, 必须使用绝对路径对象
StringgetPath()返回全路径
StringgetParentFile()
booleanisHidden()是否为隐藏文件
longlastModified()返回最后修改时间戳
booleanisDirectory()是否为一个文件夹
booleanmkdir()创建文件夹, 只能创建一个不能递归创建
booleanmkdirs()递归创建文件夹
booleanrenameTo(File dest)剪切, 移动文件
String[]list()将文件夹下的文件返回成一个字符串数组
File[]listFiles()将文件夹下的文件返回成一个 File 对象数组
String[]list(FilenameFilter filter)过滤文件
File[]listFiles(FilenameFilter filter)过滤文件

IO流分类:

  • InputStream 字节输入流
  • OutputStream 字节输出流
  • Reader 字符输入流
  • Writer 字符输出流

字节流:

InputStream(抽象类):

直接子类:

  • AudioStream
  • ByteArrayInputStream
  • FileStream
  • FilterInputStream
  • ObjectInputStream
  • PipedInputStream
  • SequenceInputStream
  • StringBufferInputStream

write() 写文件

int read() 读文件

close() 关闭流

flush() 刷新缓冲区

FileInputStream:

FileInputStream(String name)

FileInputStream(File file)

read() 读取文件

class Test {
    void test() {
        InputStream file = null;
        try {
            file = new FileInputStream(new File("./a.txt")); // 创建一个输入流对象
            byte[] buf = new byte[1024]; // 用于缓冲, 大小用2的整数倍, 最好用4k(4k对齐)
            int len = 0;
            while ((len = file.read(buf)) != -1) {
                // System.out.write(buf); // 此方法可能导致读取内容超出
                System.out.write(buf, 0, len);
                String str = new String(buf, 0, len);
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (file != null) {
                try {
                    file.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

OutputStream(抽象类):

  • FileOutputStream

FileOutputStream:

class Test {
    void test() {
        String msg = "你好";
        FileOutputStream file = null;
        try {
            file_out = new FileOutputStream(new File("b.txt"));
            file_in = new FileInputStream(new File("a.txt"));
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = file_in.read(buf)) != -1) {
                file_out = write(buf, 0, len);
            }
            System.out.ptintln("写入数据成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (file_in != null) {
                try {
                    file_in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (file_out != null) {
                try {
                    file_out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FilterInputStream & FilterOutputStream:

装饰流, 又称为过滤流

不能 直接使用, 主要的作用就是用来装饰节点流

本质是一种装饰者设计模式的体现. 对原有对象的功能进一步的装饰增强

GOF 23 设计模式:

  • 单例设计模式
  • 装饰者设计模式

子类:

  • BufferedInputStream
  • BufferedOutputStream
  • DataInputStream
  • DataOutputStream
BufferedInputStream & BufferedOutputStream:
class Test {
    void test() {
        BufferedInputStream bis = null; // 缓冲池
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream("a.txt")); // 建议把字节流写在里面, 这样不用单独关闭
            bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
            byte[] buf = new byte[1024 * 8];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                bos, write(buf, 0, len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 缓存流必须关闭, 因为JVM
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
DataOutputStream:

可以不用转换成字节数组直接就进行写入

class Test {
    void test() {
        BufferedOutputStream bos = null;
        int msg = 1000000;
        try {
            dos = new DataOutputStream(new FileOutputStream("b.txt"));
            dos, writeInt(msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
DataInputStream:
class Test {
    void test() {
        BufferedOutputStream bos = null;
        try {
            dis = new DataInputStream(new FileInputStream("a.txt"));
            System.out.println(dis.readInt());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

字符流:

计算机底层使用的二进制数据(字节数据)

字符流是为了加快流的操作, 而设计的专门用来操作字符串的一种流

注意: 字符串存在编码问题, 需要保证在读取和写入编码一致

建议使用装饰流按行读取

Reader(输入流):

class Test {
    void test() {
        Reader reader = null;
        try {
            reader = new FileReader(new File("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/a.txt"));
            char[] buf = new char[1024];
            int len = 0;
            while ((len = reader.read(buf)) != -1) {
                writer.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Writer(输出流):

class Test {
    void test() {
        Reader reader = null;
        Writer writer = null;
        try {
            writer = new FileWriter("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/b.txt");
            reader = new FileReader(new File("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/a.txt"));
            char[] buf = new char[1024];
            int len = 0;
            while ((len = reader.read(buf)) != -1) {
                writer.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

BufferedReader & BufferedWriter:

class Test {
    void test() {
        BufferedReader reader = null;
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/b.txt"));
            reader = new BufferedReader(new FileReader(new File("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/a.txt")));
            char[] buf = new char[1024];
            int len = 0;
            while (reader.readLine(buf) != null) {
                writer.write(buf + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

PrintWriter(打印输出流):

可以直接操作文件, 也可以操作对象

关闭时不会抛出异常

class Test {
    void test() {
        Reader reader = null;
        PrintWriter writer = null;
        try {
            PtintWriter = new PrintWriter("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/b.txt");
            reader = new BufferedReader(new FileReader(new File("/Users/erzbir/Desktop/IntelliJ Java/JavaTest/a.txt")));
            char[] buf = new char[1024];
            while (reader.readLine(buf) != null) {
                writer.println(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOExcetion e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

转换流:

将字节流转换为字符流操作

当操作的是文本数据的时候使用

InputStreamReader:

可以将字节输入流转换为字符输入流

class Test {
    void test() throws IOException {
        BufferedReader br = null;
        br = new BufferedReader(new InputStreamReader(System.in));
        String str = null;
        while ((str = br.readLine()) != null) {
            System.out.println(str);
        }
        br.close();
    }
}

OutputStreamWriter:

字节输出流转换成字符输入流

class Test {
    void test() throws IOException {
        BufferedReader br = null;
        PrintWriter out = null;
        br = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
        String str = null;
        while ((str = br.readLine()) != null) {
            out.println(str);
        }
        br.close();
        out.close();
    }
}

对象流:

ObjectInputStream:

class Test {
    void test() {
        String msg;
        ObjectOutputStream ois = null;
        try {
            ois = new ObjectOutputStream(new FileOutputStream("a.txt"));
            msg = ois.readObject();
            System.out.ptintln(msg);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.ptintStackTrace();
                }
            }
        }
    }
}

ObjectOutputStream

class Test {
    void test() {
        String msg = "1asda";
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
            oos.writeObject(msg);
            System.out.ptintln("保存成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.ptintStackTrace();
                }
            }
        }
    }
}

序列化:

如果一个类没有实现 Serializable 接口,那么它就不能被序列化,写入文件的时候会报异常.如果一个类实现了 Serializable 接口,那么这个类的所有属性和方法都可以自动被序列化

对象序列化:

Serialize: 将虚拟对象转换为一种可以直接传输或者保存的数据(字节, 字符)的过程

对象反序列化:

将序列化后的字节或者字符数据源重新转换为对象

对象持久化:

transient关键字:

被这个关节字修饰的属性, 无法持久化

将数据永久保存(存到磁盘)

java官方提供的序列化, 是将java对象转换为字节数据

注意: java对象序列化必须实现可序列化接口(Serializable), 这是一个标记接口自动调用底层

try-with-resources:

jdk7的新特性, 如果使用这种结构, 打开的资源会自动完成关闭

class Test {
    void test() {
        try (InputStream is = new FileInputStream("a.txt")) {
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = is.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

开发中的问题:

在开发过程中, 如果直接将一些确定的值写在代码中, 代码的设计可能有问题, 如果生产环境, 要再次修改值会非常麻烦, 需要重新编译. 这种叫做硬编码

开发环境: development environment

测试环境: test environment

生产环境: product environment

如果值永久不变:

  • 做成常量
  • 做成枚举

如果有可能变:

可以做成配置文件

Java配置文件:

  • xml

  • json

  • yaml

  • properties