阶段二-Day02-I/O流

一.File文件类

1.1File文件类简介

File文件类是I/O流的基础,数据的写入/读取都是对文件的操作,所以得先去了解文件,再去了解IO流,最后使用IO流完成对数据的写入/读取操作。

1.2File文件类的介绍

在Java中,File就代表一个文件类,这里的文件既包含了普通文件,又包含了文件目录

1.3File文件类的作用

可实现对文件的基本操作(创建文件、删除文件、获取文件长度、更改文件的名字等等),都可以通过File文件类去完成,因为File文件类提供了很多操作文件的方法。

1.4File文件类的常用方法

1.4.1 createNewFile()

在指定的盘符路径下,创建一个新文件

public class Demo1 {
    public static void main(String[] args) {
     File file = new File("D://学习/file.txt");
     //文件可能为空,就是路径下并没有这个文件,可能会报错,所以要处理异常
        try {
            boolean flag = file.createNewFile();
            if (flag){
                System.out.println("创建成功");
            }else{
                System.out.println("创建失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建成功

1.4.2 exists()

判断文件是否存在

public class Demo2 {
    public static void main(String[] args) {
     File file = new File("D://学习/file.txt");
    //判断文件是否存在
        boolean flag = file.exists();
        if (flag){
            System.out.println("文件存在");
        }else {
            System.out.println("文件不存在");
        }
     }
}

 我们刚才已经创建过了,显然是存在的

1.4.3  mkdirs()

在指定的盘符路径下,创建层级文件夹

public class Demo3 {
    public static void main(String[] args) {
        File file = new File("D://学习/a/b/c/d");

        boolean flag = file.mkdirs();
        if (flag){
            System.out.println("层级文件夹创建成功");
        }else{
            System.out.println("层级文件夹创建失败");
        }
    }
}

多了a文件夹

 a中还有b(后面的都成功了)

1.4.4 mkdir

在指定的盘符路径下,创建文件夹

public class Demo4 {
    public static void main(String[] args) {
        /* File file = new File("D://学习/b/b/c/d");*/
        //不能创建层级文件夹
        File file = new File("D://学习/b");
        boolean flag = file.mkdir();
        if (flag) {
            System.out.println("文件夹创建成功");
        } else {
            System.out.println("文件夹创建失败");
        }
    }
}

创建成功 

1.4.5  isFile()

 判断指定的文件是否是普通的文件
 

public class Demo5 {
    public static void main(String[] args) {
        File file1 = new File("D://学习/a");
        File file2 = new File("D://学习/file.txt");
        //isFile()返回值是boolean,判断是否是普通文件
        System.out.println(file1.isFile());
        System.out.println(file2.isFile());
    }
}

可以看出file.txt是普通文件,层级目录a并不是普通文件

1.4.6   isDirectory()

判断指定的文件是否是层级文件目录

public class Demo6 {
    public static void main(String[] args) {
        File file1 = new File("D://学习/b");
        File file2 = new File("D://学习/a");
        File file3 = new File("D://学习/file.txt");
        //isDirectory()返回值boolean类型
        System.out.println(file1.isDirectory());
        System.out.println(file2.isDirectory());
        System.out.println(file3.isDirectory());
    }
}

层级文件夹和空文件夹都算层级文件夹

1.4.7   delete()

删除指定路径下普通的文件和空文件夹(非层级目录)

public class Demo7 {
    public static void main(String[] args) {
        //层级目录不能删除
        File file2 = new File("D://学习/a");
        File file3 = new File("D://学习/file.txt");
        file2.delete();
        file3.delete();
    }
}

file.txt已经被删除

1.4.8   length()

在指定路径下,获取文件内容的大小

public class Demo8 {
    public static void main(String[] args) {
        File file = new File("D://学习/file.txt");
        //返回值是long类型
        long l = file.length();
        System.out.println(l);
    }
}

字节为:3

输出结果:3

1.4.9   renameTo(File dest)

修改文件的名字

public class Demo9 {
    public static void main(String[] args) {
        File file = new File("D://学习/file.txt");
        //返回值为boolean
        boolean flag = file.renameTo(new File("D://学习/123.txt"));
        System.out.println(flag);
    }
}

修改成功

1.4.10   listFiles()

获取指定路径的下一层路径

public class Demo10 {
    public static void main(String[] args) {
        File file = new File("D://学习/a");
        File[] files = file.listFiles();
        //输出a下层所有文件
        for (int i = 0; i < files.length ; i++){
            System.out.println(files[i]);
        }
    }
}

所以它的返回值是一个File类型的数组

1.5File 文件类的练习

1.5.1 文件存在与否的默认值问题

1.5.2  关于File类的构造方法的

1.6 FIle文件类的高级应用

递归删除文件

delete()无法直接删除层级目录,所以要想删除层级目录需要用到递归

public class Demo2 {
    public static void delete1(File file){
        File[] files = file.listFiles();
        if (files != null && files.length != 0){
            delete1(files[0]);
        }
        file.delete();
    }

    public static void main(String[] args) {
        File file = new File("D://学习/a");
        delete1(file);
    }
}

该代码有一个弊端,每次只能删除第一个文件,如果一个文件夹里面有好几个文件无法全部删除

优化代码

public class Demo1 {
    //定义一个方法
    public static void delete(File file){
        File[] files = file.listFiles();
        if (files != null){
            for (File f : files) {
               delete(f);
            }
        }
        file.delete();

    }
    public static void main(String[] args) {
        //递归删除
        File file = new File("D://学习/a");
        delete(file);
    }
}

总结:

二.Java中的流 

2.1 流的概念

在Java中,利用程序完成对数据的(存储)操作所使用的工具就是流。

2.2 解读

通过程序向文件入数据

通过程序取文件中的数据

2.3 流的划分 

按照方向划分:

流是有方向的:

输入流(对数据的读操作),利用写好的程序,把文件中的数据读取出来(文件中数据已经存在,通过程序去读取,最终显示出来)

输出流(对数据的写操作),利用写好的程序,把程序中指定的数据写到文件中(文件中还没有数据,通过程序把指定好的数据写入文件)

按照类型来划分:

 

2.4  字节流 

 2.4.1字节输出流:

import java.io.File;
import java.io.FileOutputStream;

public class ByteOutputStream {
    public static void main(String[] args) throws Exception {
        //1.创建对象
        //路径如果写错了,会报错
        //FileNotFoundException: D:\a\file.txt (系统找不到指定的路径。)
        //写入时要满足这个文件不存在,则会创建该文件,但是要保证路径正确
        FileOutputStream fos = new FileOutputStream("D://学习/a/file.txt");
        FileOutputStream fos1 = new FileOutputStream(new File("D://学习/a/file.txt"));
        //两种定义方式都可以
        //2.写入数据
        //虽然是97,写进去的是a
        fos.write(97);
        //3.释放资源
        fos.close();
    }
}

数字对应的ASCII符号

三种写入方式:

public class ByteOutputStream1 {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("D://学习/a/file.txt");

        /*
        * 三种写入方式:
        *  void write(int b)                       一次写一个字节数据
           void write(byte[] b)                    一次写一个字节数组数据
           void write(byte[] b, int off, int len)  一次写一个字节数组的部分数据
           参数一:数组
           参数二:起始索引
           参数三:个数
        *
        * */
        fos.write(97);

        //写入字节数组
        byte[] b = {97,98,99,100};
        fos.write(b);

        //写入字节数组的一部分
        fos.write(b,1,2);

        //关闭资源
        fos.close();
    }
}

换行和续写:

写入数据时每次数据都会重置,为了保存数据,可以进行续写

public class ByteOutputStream2 {
    public static void main(String[] args) throws Exception {
        //打开续写开关
        FileOutputStream fos = new FileOutputStream("D://学习/a/file.txt",true);

        /*
        * 换行:\r\n
        * 写其中一个也行
        *
        * 续写:创建对象的第二个参数
              默认false:表示关闭续写,此时创建对象会清空文件
              手动传递true:表示打开续写,此时创建对象不会清空文件
        * */
        //一个write代表一次写入操作
        fos.write(97);

        String s = "\r\n";
        byte[] b1 = s.getBytes();
        fos.write(b1);
        //写入字节数组
        byte[] b2 = {97,98,99,100};
        fos.write(b2);

        //写入字节数组的一部分
        fos.write(b2,1,2);

        //关闭资源
        fos.close();
    }
}

2.4.2字节输入流:

public class ByteInputStream {
    public static void main(String[] args) throws Exception {
        /*
        *字节输入流FileInputStream
        * 读取文件中的数据
        *
        * */
        //1.创建对象
        FileInputStream fis = new FileInputStream("D://学习/a/file.txt");
        //2.读取数据
        //read()返回值为int类型
        //读取到的是对应的十进制数字
        int b1 = fis.read();
        System.out.println(/*(char)*/b1);

        int b2 = fis.read();
        System.out.println(/*(char)*/b2);

        int b3 = fis.read();
        System.out.println(/*(char)*/b3);

        int b4 = fis.read();
        System.out.println(/*(char)*/b4);

        int b5 = fis.read();
        System.out.println(/*(char)*/b5);

        int b6 = fis.read();
        System.out.println(/*(char)*/b6);//-1

        //3.释放资源
        fis.close();

    }
}

读取到了a之后,13和10代表换行

一共就读取了6个,十分不方便

优化:

public class ByteInputStream1 {
    public static void main(String[] args) throws Exception {
        //读取的时候,如果没有这个文件则会直接报错
        FileInputStream fis = new FileInputStream("D://学习/a/file.txt");
        //该方法可以获取能读到的所有字节的数量
        int available = fis.available();
        System.out.println(available);
         /*
        * 三种读取方式,和字节输出流一样
        *  void read(int b)                       一次写一个字节数据
           void read(byte[] b)                    一次写一个字节数组数据
           void read(byte[] b, int off, int len)  一次写一个字节数组的部分数据
           参数一:数组
           参数二:起始索引
           参数三:个数
        *
        * */
        //使用字节数组将能读取到的字节存起来
        byte[] b = new byte[available];
        //这里使用的是第二种,一次读取一个字节数组,效率更高
        fis.read(b);
        //读取完之后,会把读取到的东西赋值给b数组
        //将得到的字节数据转换成字符数据
        String value = new String(b);
        System.out.println("读到的数据为:" + value);
        //3.释放资源
        fis.close();

    }
}

循环遍历读取数据

public class ByteInputStream3 {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("D://学习/file.txt");
        //while循环读取,read()返回值为int类型,如果为-1,则是读取不到
        while ((fis.read()) != -1) {
            System.out.println((char)fis.read());
        }
        //3.释放资源
        fis.close();
    }
}

2.5字节流实现拷贝操作

图片的拷贝

public class Demo {
    public static void main(String[] args) throws Exception{
        long start = System.currentTimeMillis();
        //1.创建对象
        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\2.jpg");

        //2.拷贝
        //核心思想:边读边写
        int b;
        while((b = fis.read()) != -1){
            fos.write(b);
        }

        //3.释放资源
        //规则:先开的最后关闭
        fos.close();
        fis.close();

        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

 

 如果文件过大,一个字节一个字节的拷贝速度太慢了

public class Demo1 {
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();

        //1.创建对象
        FileInputStream fis = new FileInputStream("D:\\1.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\2.jpg");
        //2.拷贝
        int len;
        //一次拷贝一个字节数组,这和后面的字符流有点儿像,提高效率
        byte[] bytes = new byte[1024 * 1024 * 5];
        while((len = fis.read(bytes)) != -1){
            fos.write(bytes,0,len);
        }
        //3.释放资源
        fos.close();
        fis.close();

        long end = System.currentTimeMillis();

        System.out.println(end - start);
    }
}

 2.6 字符集问题

不同编码集,转换形式都不一样 

一旦编码和解码的方式不统一,就会出现乱码问题

 乱码问题的解决

public class Demo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        /**
         Java中编码的方法
         public byte[] getBytes()                        使用默认方式进行编码
         public byte[] getBytes(String charsetName)      使用指定方式进行编码
         编码:将认识的内容变成你不认识的内容(由字符串到字节)

         Java中解码的方法
         String(byte[] bytes)                            使用默认方式进行解码
         String(byte[] bytes, String charsetName)        使用指定方式进行解码
         解码:将不认识的内容变成你认识的内容(由字节到字符串-字节电报破译)
         */
        //1.编码
        String str = "ai你哟";
        byte[] bytes1 = str.getBytes();
        System.out.println(Arrays.toString(bytes1));// public byte[] getBytes() 使用默认方式进行编码

        byte[] bytes2 = str.getBytes("GBK");//public byte[] getBytes(String charsetName) 使用指定方式进行编码
        System.out.println(Arrays.toString(bytes2));


        //2.解码
        String str2 = new String(bytes1); //String(byte[] bytes)    使用默认方式进行解码
        System.out.println(str2);

        //String str3 = new String(bytes1,"GBK"/*编码和解码不一致*/);
        // String(byte[] bytes, String charsetName) 使用指定方式进行解码
        /* String str3 = new String(bytes1,"UTF-8");*/
        String str3 = new String(bytes2,"UTF-8");
        System.out.println(str3);
    }
}

三.字符流

 3.1字符输入流

public class Demo {
    public static void main(String[] args) throws Exception{
        /**
         * 需求:利用字符流完成指定路径下数据的读取
         第一步:创建对象
         public FileReader(File file)        创建字符输入流关联本地文件
         public FileReader(String pathname)  创建字符输入流关联本地文件

         第二步:读取数据
         public int read()                   读取数据,读到末尾返回-1
         public int read(char[] buffer)      读取多个数据,读到末尾返回-1

         第三步:释放资源
         public void close()                 释放资源/关流
         */
        //1.创建对象并关联本地文件
        FileReader fr = new FileReader("D:\\file.txt");
        //2.读取数据 read()
        //字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
        //如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节
        //read()细节:
        //1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
        //2.在读取之后,方法的底层还会进行解码并转成十进制。
        //  最终把这个十进制作为返回值
        //  这个十进制的数据也表示在字符集上的数字
        //      英文:文件里面二进制数据 0110 0001
        //          read方法进行读取,解码并转成十进制97
        //      中文:文件里面的二进制数据 11100110 10110001 10001001
        //          read方法进行读取,解码并转成十进制27721
        // 我想看到中文汉字,就是把这些十进制数据,再进行强转就可以了
        int ch;
        while((ch = fr.read()) != -1){
/*            System.out.print(ch);//输出数字的值*/
            System.out.print((char)ch);//将数字转化为字母
        }
        //3.释放资源
        fr.close();
    }
}

字符输入流底层已将字符集转换好了,所以字符集可以不管编码

也可以按照数组读取提高效率

public class Demo2 {
    public static void main(String[] args) throws Exception{
        //1.创建对象
        FileReader fr = new FileReader("D:\\a.txt");
        //2.读取数据
        char[] chars = new char[2];
        int len;
        //read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
        //空参的read + 强转类型转换
        while((len = fr.read(chars)) != -1){
            //把数组中的数据变成字符串再进行打印
            System.out.print(new String(chars,0,len));
        }
        //3.释放资源
        fr.close();
    }
}

3.2字符输出流

 

public class Demo1 {
    public static void main(String[] args) throws IOException {
          /*
            第一步:创建对象
                public FileWriter(File file)                            创建字符输出流关联本地文件
                public FileWriter(String pathname)                      创建字符输出流关联本地文件
                public FileWriter(File file,  boolean append)           创建字符输出流关联本地文件,续写
                public FileWriter(String pathname,  boolean append)     创建字符输出流关联本地文件,续写
            第二步:读取数据
                void write(int c)                           写出一个字符
                void write(String str)                      写出一个字符串
                void write(String str, int off, int len)    写出一个字符串的一部分
                void write(char[] cbuf)                     写出一个字符数组
                void write(char[] cbuf, int off, int len)   写出字符数组的一部分
            第三步:释放资源
                public void close()                 释放资源/关流
              
        */
        FileWriter fw = new FileWriter("D:\\a.txt",true);
        fw.write(25105);//我
        fw.write("你好啊???");
        char[] chars = {'a','b','c','我'};
        fw.write(chars);
        fw.close();
    }
}

写入数据

四.字符流原理:

4.1字符输入流原理

 每次都尽可能的填满缓冲区

让第8913个数据为b 

public class Demo {
    public static void main(String[] args) throws Exception{
        /*//1.创建对象
        FileWriter fileWriter = new FileWriter(new File("D://a.txt"));
        for (int i = 0; i < 8193; i++) {
            //2.写入数据
            fileWriter.write("a");
        }
        //3.关闭桥梁
        fileWriter.close();*/

        FileReader fileReader = new FileReader(new File("D://a.txt"));

        for (int i = 0; i < 8192; i++) {
            //2.读入数据
            int read = fileReader.read();
            System.out.println((char)read);
        }
        System.out.println("=============");
        //在8192之外的数据开始,会把之前的缓冲区数组从头开始赋值
        fileReader.read();
        fileReader.close();
    }
}
在8192之外的数据开始,会把之前的缓冲区数组从头开始赋值

 4.2字符输出流原理

 

public class Demo {
    public static void main(String[] args) throws Exception{
        FileWriter fw = new FileWriter(new File("D://b.txt"));
        for (int i = 0; i < 8192; i++) {
            fw.write(97);
        }
        fw.flush();
        //flush是刷新缓冲区的作用
        //哈哈能被写入
        fw.write("哈哈");
        fw.close();
        //这里会报错,因为通道已经关闭了,这里再继续写的话就会报错
        fw.write("呵呵");
    }
}

五.字节流和字符流的应用

5.1文件的拷贝

将a文件夹拷贝给b

 

public class Test01 {
    public static void main(String[] args) throws IOException {
        //拷贝一个文件夹,考虑子文件夹

        //1.创建对象表示数据源

        File src = new File("D:\\学习\\src");
        //2.创建对象表示目的地
        File dest = new File("D:\\学习\\dest");

        File dest1 = new File(dest,"哈哈哈");
        dest1.mkdirs();
        //3.调用方法开始拷贝
        copydir(src,dest);
    }

    /*
     * 作用:拷贝文件夹
     * 参数一:数据源
     * 参数二:目的地
     *
     * */
    private static void copydir(File src, File dest) throws IOException {
        dest.mkdirs();
        //递归
        //1.进入数据源
        File[] files = src.listFiles();
        //2.遍历数组
        for (File file : files) {
            if(file.isFile()){
                //3.判断文件,拷贝
                FileInputStream fis = new FileInputStream(file);
                //new File(dest,file.getName()) 在dest的子文件夹下创建file.getName()的名称的子文件夹
                FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));
                byte[] bytes = new byte[1024];
                int len;
                while((len = fis.read(bytes)) != -1){
                    fos.write(bytes,0,len);
                }
                fos.close();
                fis.close();
            }else {
                //4.判断文件夹,递归
                copydir(file, new File(dest,file.getName()));
            }
        }
    }
}

 5.2文件的加密

public class Demo {
    public static void main(String[] args) throws Exception{
        //可以利用^完成加密、解密,相同为0,不同为1
        //两个反过来就是解密
        FileInputStream fileInputStream = new FileInputStream("D:\\2.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\3.jpg");

        //加密
        int num ;
        //num = fileInputStream.read()每次都要循环
        while((num = fileInputStream.read()) != -1){
            fileOutputStream.write(num ^ 2);
        }

        fileOutputStream.close();
        fileInputStream.close();
    }
}

5.3先读,之后排序,再写入

public class Demo {
    public static void main(String[] args) throws Exception{
        //先读数据
        FileReader fileReader = new FileReader(new File("D://c.txt"));
        //创建StringBuilder对象
        StringBuilder sb = new StringBuilder();
/*        String s = "";*/
        int num;
        while((num = fileReader.read()) != -1){
            /*System.out.print((char)num);*/
            /*s = s + (char)num ;*/
            sb.append((char)num);
        }
        /*String[] split = s.split("-");*/
        //将StringBuilder变成字符串
        String str = sb.toString();
        String[] split = str.split("-");
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (String s : split){
            arrayList.add(Integer.parseInt(s));
        }
        //集合排序
        Collections.sort(arrayList);
        System.out.println(arrayList);

        //写入数据
        FileWriter fileWriter = new FileWriter(new File("D://c.txt"));
        for (int i = 0; i < arrayList.size(); i++){
            if (i != arrayList.size() - 1){
                //不能直接写Integer,要先变一下类型
                fileWriter.write(arrayList.get(i) + "-");
            }else {
                fileWriter.write(arrayList.get(i) + "");
            }
        }
        fileWriter.close();
        fileReader.close();
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值