zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Java基础—IO小结(一)概述与节点流

JAVA节点基础IO 小结 概述
2023-09-27 14:23:45 时间

一、File类的使用 

  由于file类是一个基础类,所以我们从file类开始了解。(SE有完善的中文文档,建议阅读)

  构造器:

  

   常用方法:——完整方法请参见API API API!!!

      File做的是面上的事——文件的新建、删除、重命名等。有关文件内容的操作,需要流来进行,所以,它经常作为形参。

  

   文件名:

  测试文件:

  

  测试代码:

   @Test
    public void test1() {
        // 通过绝对路径创建File对象——对应一个文件或者文件夹
        File file = new File("D:\\test\\hello.txt");
        // getName()——文件或目录名
        System.out.println("#getName:"+file.getName());
        //     getPath()——路径字符串,若是相对路径,返回相对路径字符串
        System.out.println("#getPath:"+file.getPath());
        // getAbsoluteFile()——绝对路径形式,返回File
        System.out.println("#getAbsoluteFile() "+file.getAbsoluteFile());
        // getAbsolutePath()——绝对路径字符串
        System.out.println("#getAbsolutePath() "+file.getAbsolutePath());
        // getParent() ——返回父目录
        System.out.println("#getParent() "+file.getParent());

    }
View Code

   测试结果:

  

  文件检测:

  测试文件:

  

 

  测试代码:

 @Test
    public void test2() {
        File file1 = new File("D:\\test\\hello.txt"); // 文件
        File file2 = new File("D:\\test\\childDir"); // 文件夹
        //     exists()——文件或目录是否存在
        System.out.println("#exists()"+file1.exists());
        // canRead() canWrite() ——是否可读可写
        System.out.println("#canRead()"+file1.canRead());
        System.out.println("#canWrite()"+file1.canWrite());
        //     isFile() isDirectory() ——是否是文件/目录
        System.out.println("#isFile()"+file1.isFile());
        System.out.println("#isFile()"+file2.isFile());
        System.out.println("#isDirectory()"+file1.isDirectory());
        System.out.println("#isDirectory()"+file2.isDirectory());
    }
View Code

   测试结果:

  

  获取常规文件信息:

  测试文件:上文hello.txt

    测试代码:

@Test
    public void test3() {
        File file = new File("D:\\test\\hello.txt");
        // lastModified() ——文件最后修改时间
        System.out.println("lastModified() :"+ new Date(file.lastModified()));
        // length()——文件长度(字节)
        System.out.println("length:"+file.length());
    }
View Code

  测试结果:

  

  文件操作相关:

  测试代码:

 @Test
    public void test4() throws IOException {
        File file = new File("D:\\test\\hello1.txt"); //文件不存在
        // createNewFile()  ——不存在时创建新文件
        if (!file.exists()) {
            boolean b = file.createNewFile();
            System.out.println("创建空文件结果:"+ b);
        }
        // delete() ——文件长度(字节)
        System.out.println("delete() :" + file.delete());
    }
View Code

  测试结果:

  

  目录操作相关:

  测试文件:

  

  测试代码:

 @Test
    public void test5() throws IOException {
        File file1 = new File("D:\\test\\childDir"); // 文件夹
        if (!file1.exists()) {
            // mkdir()——创建一个文件目录 mkdirs()——递归创建
            boolean b = file1.mkdir();
            System.out.println("新建文件夹结果:"+ b);
        }
        File file = new File("D:\\test");
        // 与Linux命令的ls类似,list返回字符串,listFiles返回文件
        String[] files = file.list();
        for (String s : files) {
            System.out.println(s);
        }
    }
View Code

  测试结果:

  

二、IO流的分类

    读取外部设备中到程序中,称之为 input,输入;从程序向外输出到外部,称之为 ouput,输出;

  也就是,站在程序的角度来理解输入输出!

   A.根据处理数据类型的不同分为:字符流和字节流

   B.根据数据流向不同分为:输入流和输出流

   C.按功能分:节点流(一线的,离源最近的)和处理流

  

  都是由四个最基本的 抽象类派生而成

  

三、节点流的使用

  

  请注意:由于流不是JVM的资源,不会被回收,所以:必须手动显式关闭!

   1.fis与fos

  FileInputStream

  构造器:

  

  方法摘要:输入流对应读的方法

  

  read()方法:

  @Test
    public void testFis1() throws Exception{
        // 从硬盘读取一个文件(File类与文件建立联系),将其文件内容读取到程序中
        File file = new File("D:\\test\\hello.txt");
        // 通过file构建一个输入流
        FileInputStream fis = new FileInputStream(file);
        // 调用fis的方法进行文件的操作
        /*
        * read():读取文件的一个字节(java中int为4字节),到结尾时返回-1
        * */
//        int b = fis.read();
//        while (b != -1) {
//            System.out.print((char)b);
//            b = fis.read();
//        }
        int b;
        while ((b = fis.read()) != -1) {
            System.out.print((char)b);
        }
        // 必须手动关闭流!
        fis.close();
    }
View Code

  结果:

  

  //实际上,txt中文件为Hello World,仔细看 72便是H的ASCII值(char型转为Int型了)

  若要显示英文字符,可以进行强转:

 System.out.print((char)b);

  当然,这里直接thorws的做法是及其不靠谱的,至少,当前面出现异常时,后续的代码(如colse())不会继续执行,也就是说,资源无法关闭!

  我们稍加改进:—— IO的操作请注意写法!

 @Test
    public void testFis2(){
        FileInputStream fis = null;
        try {
            // 从硬盘读取一个文件(File类与文件建立联系),将其文件内容读取到程序中
            File file = new File("D:\\test\\hello.txt");
            // 通过file构建一个输入流
            fis = new FileInputStream(file);
            // 调用fis的方法进行文件的操作

            int b;
            while ((b = fis.read()) != -1) {
                System.out.print((char)b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 必须手动关闭流!
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
View Code

  当然,一个一个字节读,在实际中是不可能的,我们可以使用它的重载方法:

  

  @Test
    public void testFis3() {
        FileInputStream fis = null;
        try {
            File file = new File("D:\\test\\hello.txt");
            fis = new FileInputStream(file);
            // 定义每次读取的字节数组,这里定义长度为5
            byte[] bytes = new byte[5];
            int len; // 每次读取的字节长度
            while ((len = fis.read(bytes)) != -1) {
                /* 这里必须注意bytes.length与len的区别,len是实际读到的长度,
                   bytes.length是数组长度,可能会有之前读到的老的字符,读到的字节是依次放入bytes中,
                   将原先数组的进行替换,若未替换完,则保留了老的字节,不能遍历!
                */
                for (int i = 0; i < len; i++) {
                    System.out.print((char)bytes[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 手动关闭流
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
View Code

  //相关注意的问题请看注释!

  FileOutputStream

  构造器:

  

  方法摘要:对应写的方法

  

  测试代码:

 @Test
    public void testFos1() {
        // 文件可以不存在,将会自动创建
        File file = new File("D:\\test\\hello1.txt");
        FileOutputStream fos = null;
        try {
            // 同样,使用文件作为构造器,关联上一个文件
            fos = new FileOutputStream(file);
            // 使用字节数组写入数据到文件
            fos.write(new String("I love China").getBytes());
            System.out.println("fos done!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) { //增加空判断,防止空指针异常
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
View Code

 //稍微改进异常处理时流的关闭引发的NPE

   结果:若文件存在不是追加,而是直接覆盖文件

  

  fos与fis实现文件的复制:

  测试代码:

 @Test
    public void testFisAndFos1() {
        // 已经存在,用于输入流读取
        File file1 = new File("D:\\test\\0.jpg");
        // 不存在,用于输入流写出
        File file2 = new File("D:\\test\\1.jpg");
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(file1);
            fos = new FileOutputStream(file2);
            int len;
            byte[] bytes = new byte[5];
            while ((len = fis.read(bytes)) != -1) {
                // 将取到的字节写入新的文件,注意读的长度
                // 考虑 fos.write(bytes);的写法的错误之处
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
View Code

  // 后续将会升级为缓冲流

  测试结果:

  

  // 无论字节或者字符,都可以使用字节流进行处理

  2.fr与fw

  FileReader与FileWriter处理的步骤与上述是基本一样的,不同的是字符流处理的单位稍有差异

  构造器:

  

  

  FileReader

  测试代码:

   @Test
    public void testFr1() {
        File file = new File("D:\\test\\hello.txt");
        FileReader fr = null;
        try {
            // 同样的,根据文件构建一个输入流
            fr = new FileReader(file);
            int len;
            // 实际操作请根据文件大小修改字符数组大小
            char[] cbuf = new char[5];
            while ((len = fr.read(cbuf)) != -1) {
                String s = new String(cbuf, 0, len);
                System.out.print(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
View Code

  测试结果即为输出文本文件到控制台

  FileReader与FileWriter进行文本文件复制与之前类似,只是数组类型不同:

  @Test
    public void testFrAndFw1() {
        // 需要关联的文件
        File file1 = new File("D:\\test\\hello.txt");
        File file2 = new File("D:\\test\\hello3.txt");
        FileReader fr = null;
        FileWriter fw = null;
        try {
            // 通过文件创建流
            fr = new FileReader(file1);
            fw = new FileWriter(file2);
            int len;
            char[] cbuf = new char[5];
            while ((len = fr.read(cbuf)) != -1) {
                fw.write(cbuf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
View Code