IO专题

作者: 攻城老狮 | 来源:发表于2021-05-27 08:09 被阅读0次

    1 文件

    1.1 文件流的相关概念

    流:数据在数据源(文件)和程序(内存)之间经历的路径

    输入流:数据从数据源(文件)到程序(内存)的路径

    输出流:数据从程序(内存)到数据源(文件)的路径

    1.2 常用的文件操作

    1.2.1 创建文件对象

    public class File_ {
        public static void main(String[] args) throws IOException {
            //1.根据路径构建一个File对象
            String pathname = "d:/fileTest1.txt";
            File file1 = new File(pathname);
            file1.createNewFile();
            //2.根据父目录文件和子路径构建
            File parent = new File("d:/");
            File file2 = new File(parent, "fileTest2.txt");
            file2.createNewFile();
            //3.根据父目录和子路径构建
            File file3 = new File("d:/", "fileTest3.txt");
            file3.createNewFile();
        }
    }
    

    1.2.2 获取文件的相关信息

    public class File_ {
        public static void main(String[] args) throws IOException {
            String pathname = "d:/fileTest1.txt";
            File file = new File(pathname);
            //1.getName 获取文件名
            System.out.println(file.getName());
            //2.getAbsolutePath 获取文件绝对路径
            System.out.println(file.getAbsolutePath());
            //3.getParent 获取文件父级目录
            System.out.println(file.getParent());
            //4.length 文件大小(字节)
            System.out.println(file.length());
            //5.exists 文件是否存在
            System.out.println(file.exists());
            //6.isFile 判断是不是一个文件
            System.out.println(file.isFile());
            //7.isDirectory 判断是不是一个目录
            System.out.println(file.isDirectory());
        }
    }
    
    • result
    fileTest1.txt
    d:\fileTest1.txt
    d:\
    0
    true
    true
    false
    

    2 IO 流原理及流的分类

    2.1 IO 流的分类

    • 按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
    • 按数据流的流向不同分为:输入流,输出流
    • 按流的角色的不同分为:节点流,处理流(包装流)

    2.2 IO 流的体系图

    image-20210518150008681.png

    3 FileInputStream和FileOutputStream

    说明:使用这两个类可以实现对二进制文件的读入和写出,节点流

    //使用FileInputStream 和 FileOutputStream 实现对照片的拷贝
    public class FileCopy {
        public static void main(String[] args) {
            String srcPathName = "d:/testPicture.png";
            String destPathName = "d:/testPicture_new.png";
            FileInputStream fis = null;
            FileOutputStream fos = null;
            int readLen = 0;
            byte[] buf = new byte[1024];
            try {
                fis = new FileInputStream(srcPathName);
                fos = new FileOutputStream(destPathName);
                //每次读入1024字节内容至缓冲区,返回实际存储至缓冲区的字节数
                while ((readLen = fis.read(buf)) != -1) {
                    fos.write(buf, 0, readLen);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (fis != null) {
                        fis.close();
                    }
                    if (fos != null) {
                        fos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    4 FileReader 和 FileWriter

    说明:使用这两个类可以实现对字符的输入输出,FileWriter使用后,必须关闭或刷新,否则写入不到指定的文件

    public class FileReaderWriter {
        public static void main(String[] args) {
            String srcFilePath = "d:/testFile.txt";
            String destFilePath = "d:/testFile_new.txt";
            FileReader fr = null;
            FileWriter fw = null;
            int readLen = 0;
            char[] buf = new char[8];
            try {
                fr = new FileReader(srcFilePath);
                fw = new FileWriter(destFilePath);
                //每次读入8字符内容至缓冲区,返回实际存储至缓冲区的字符数
                while ((readLen = fr.read(buf)) != -1) {
                    fw.write(buf, 0, readLen);
                    //打印字符到屏幕
                    System.out.println(new String(buf,0,readLen));
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (fr != null) {
                        fr.close();
                    }
                    if (fw != null) {
                        fw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    5 节点流和处理流

    5.1 基本说明

    • 节点流:可以从一个特定的数据源读写数据,如 FileReader,FileWriter
    • 处理流/包装流:连接在已存在的流之上,为程序提供更强大的读写功能,更灵活,如 BufferedReader,BufferedWriter

    5.2 节点流和处理流的区别

    • 节点流是底层流/低级流,直接跟数据源相接
    • 处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供方便的方法实现输入输出。
    • 处理流采用修饰器模式,不会直接于数据源连接

    6 BufferedReader 和 BufferedWriter

    6.1 基本说明

    • Buffer额度Reader 和 BufferedWriter 属于字符流,是按照字符来读取数据的
    • 关闭时只需要关闭最外层流即可
    • 不能操作二进制文件,由于其是以字符的形式流动,故会造成二进制文件的损坏

    6.2 示例

    说明:使用这两个类可以实现对文本文件的读入和写出,包装流

    public class BufferedReaderWriter {
        public static void main(String[] args) {
            //获取resources目录下的文件方法(target目录下)
            String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
            String destFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile_new.txt").getPath();
            BufferedReader br = null;
            BufferedWriter bw = null;
            String line;
            try {
                br = new BufferedReader(new FileReader(srcFilePath));
                bw = new BufferedWriter(new FileWriter(destFilePath));
                while ((line = br.readLine()) != null) {
                    bw.write(line);
                    bw.newLine();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (br != null) {
                        br.close();
                    }
                    if (bw != null) {
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

    7 BufferedInputStream 和 BufferedOutputStream

    说明:使用这两个类可以实现对二进制文件的读入和写出,包装流

    public class BufferedInputStreamOutputStream {
        public static void main(String[] args) {
            String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
            String destFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile_new.txt").getPath();
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            byte[] buf = new byte[64];
            int len = 0;
            try {
                bis = new BufferedInputStream(new FileInputStream(srcFilePath));
                //true 表示追加
                bos = new BufferedOutputStream(new FileOutputStream(destFilePath,true));
                while ((len = bis.read(buf)) != -1) {
                    bos.write(buf, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (bis != null) {
                        bis.close();
                    }
                    if (bos != null) {
                        bos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    

    8 对象流 ObjectInputStream 和 ObjectOutputStream

    8.1 对象流说明

    • 将Java对象保存至文件中称为序列化,将文件中的数据(值和类型)恢复为Java对象称为反序列化

    • 序列化和普通的保存不同之处在于,普通的保存只存储值,而序列化会保存值和数据类型

    • 对象流提供了对基本类型和对象类型的序列化和反序列化

    8.2 序列化说明

    • 读写顺序要相同,按什么顺序序列化就需要按什么顺序反序列化
    • 要求序列化或反序列化对象,实现Serializable接口
    • 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
    • 序列化对象时,默认将所有属性序列化,除了static和transient修饰的成员
    • 序列化对象时,要求属性的类型需要实现序列化接口
    • 序列化具备可继承性,如果某个类已经实现序列化,则它的所有子类也默认实现序列化

    8.3 示例

    • 序列化

    说明:使用 ObjectOutputStream 序列化基本数据类型和自定义对象,包装流

    • 反序列化

    说明:使用 ObjectInputStream 反序列化上述内容,包装流

    public class ObjectInputStreamOutputStream {
        public static void main(String[] args) {
            serialFunc();
            deserialFunc();
        }
    
        //反序列化
        public static void deserialFunc(){
            String objectPath = Thread.currentThread().getContextClassLoader().getResource("objectFile.txt").getPath();
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream(objectPath));
                //反序列化基本类型
                System.out.println(ois.readInt());
                System.out.println(ois.readBoolean());
                System.out.println(ois.readUTF());
                //反序列化自定义对象
                System.out.println(ois.readObject());
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (ois !=null){
                        ois.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        //序列化
        public static void serialFunc(){
            String objectPath = Thread.currentThread().getContextClassLoader().getResource("objectFile.txt").getPath();
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(new FileOutputStream(objectPath));
                //序列化基本类型
                oos.writeInt(233);
                oos.writeBoolean(false);
                oos.writeUTF("hello world");
                //序列化自定义对象
                oos.writeObject(new Person("yorick",24));
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (oos !=null){
                        oos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    9 标准输入输出流

    9.1 基本说明

    • System.in 标准输入,类型是InputStream(BufferedInputStream),默认设备为键盘
    • System.out 标准输出,类型是PrintStream,默认设备为显示器

    10 转换流 InputStreamReader 和 OutputStreamWriter

    10.1 基本说明

    • 若本地文件采用gbk编码,则使用字符输入流读入默认采用的为utf-8编码,会导致出现乱码。可以借助 字节输入流转换编码,再使用字符输入流读入,故需要借助转换流转换
    • InputStreamReader 是 Reader 的子类,可以将 InputStream 包装为 Reader
    • OutputStreamWriter 是 Writer 的子类,可以将 OutputStream 包装为 Writer

    10.2 示例

    说明:将gbk编码的文件,读入不产生乱码

    public class InputStreamReaderOutputStreamWriter {
        public static void main(String[] args) {
            String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("testFile.txt").getPath();
            BufferedReader br = null;
            String line;
            try {
                //将其进行层层包装
                br = new BufferedReader(new InputStreamReader(new FileInputStream(srcFilePath),"gbk"));
                while ((line = br.readLine())!=null){
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (br !=null){
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    11 打印流 PrintStream 和 PrintWriter

    11.1 基本说明

    • 打印流只有输出流,没有输入流

    • PrintStream 间接继承 OutputStream,PrintWriter 继承 Writer

    相关文章

      网友评论

          本文标题:IO专题

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