I/O流的使用


前言


一、IO流的一些概念

1.什么是IO流

IO流: Input/OutputStream 输入/输出流
: 指的是一串流动的数据,在整个数据流中按照指定的方向流动传输来实现数据的写入和读取功能。
作用:实现两个对象设备之间的数据传递

2.IO流的使用场景

1、当我们使用File类时只能实现对文件的操作,包括:获取文件属性、创建/删除/移动文件等等,但不能对文件的内容做出改动。
如果想要对文件内容操作的话,比如:需要读取、删改文件内容等,此时就需要使用IO流进行操作了。
2、IO流的使用场景:需要对一个文件内容进行操作的时候。

注意事项:
IO流的操作对象是一个文件,而不是对一个文件夹进行读写的。 在使用IO流的时候注意不要与一个文件夹建立连接!!!

3.IO流的分类

我们按照不同的分类标准可以得到不同分类的IO流:

1、按传输数据的单位分为:
字节流: 传输的是字节,是以字节为单位的。可以操作任意类型的数据 ------音频,视频,文件,图片等
字符流: 传输的是字节,不同点是在传输过程中加入了编码的操作,让我们的操作更方便------文本

2、按照数据传输的方向分为:
输入流: 数据从其他设备传到内存
输出流: 数据从内存传到其他设备

其实在 java.io 包中, 有很多很多的类, 都是来描述IO流的。 但是基本上所有的IO流的类, 都是直接或间接的继承自四大父类流

字节流的两个父类:
字节输入流:InputStream
字节输出流:OutputStream

字符流的两个父类:
字符读入流:Reader
字符写出流:Writer

4.IO流使用的注意事项

1、四大父类流, 都是抽象类, 都不能实例化对象。 因此, 需要借助他们
的⼦类实现数据的读写。
2、流对象⼀旦实例化完成, 将建立⼀个程序与文件之间的连接。 这个连
接会持有这个文件。 如果这个连接不断, 此时这个文件就是⼀个被使
用中的状态, 此时将无法对这个文件进行其他的操作, 例如删除。
3、⼀个流在使用完成之后, 切记! ⼀定要进行流的关闭。


二、路径

路径: 用来描述⼀个⽂件所在的地址, ⽤来定位⼀个⽂件的。
可以分为绝对路径相对路径

1.绝对路径

绝对路径: 从磁盘的根目录开始, ⼀层层的向下查找, 直到找到这个⽂件。

//例如:
//C:\Users\Administrator\Desktop\text.txt
//C:\Users\Administrator\Desktop\aaa.jpg

2.相对路径

相对路径: 找到⼀个参照物, 相对于这个参照物的路径。
例如:

//classes\test.txt

3.二者对比

1、对于绝对路径来说:用来表示⼀个文件的地址, 只要这个使用方还在当前磁盘上, ⼀定可以找到这个⽂件。但是如果⼀旦更换⼀个文件系统,此时这个路径表示的⽂件将无法找到。

2、对于相对路径来说:只要两者的相对位置不变, 无论在哪⼀个⽂件系统中, 都可以找到这个文件。但是只要两者的相对位置发⽣了改变, 这个⽂件就⽆法被访问到。


三、分隔符

在描述路径的字符串中, 有两种分隔符, 是比较常见的: 目录分隔符 和 路径分隔符

1.目录分隔符

1、分隔开⼀个路径中的不同的文件夹, 用来描述层级关系、 包含关系。

2、在不同的操作系统中, 目录分隔符是不⼀样的。

在windows中, 使用 \作为目录分隔符。
在非windows的操作系统中, 例如: Linux、Unix.. 使用的是 **/** 作为目录分隔符。

3、理论上来讲, 在windows中, 应该使用 \ 作为目录分隔符。 但是在有些情况下, 使用/也是可以做目录分隔符的。

2.路径分隔符

1、分隔开⼀个字符串中的多个路径。

2、在不同的操作系统中, 路径分隔符是不⼀样的。

在windows中, 使用;作为路径分隔符。
在非windows的操作系统中, 例如: Linux、Unix.. 使用的是   : 作为路径分隔符。

3.分隔符的表示和获取方法

如果你的程序只需要考虑部署在windows平台, 那么只需要按照windows的规范书写就可以;
如果你的程序只需要部署到linux上, 那么只需要按照linux的规范书写就可以。
但是, 如果你的程序需要考虑在不同的平台上部署运行, 此时就需要使用以下方法进行分隔符的获取。

public static void main(String[] args) {
        System.out.println(File.separator);//获取⼀个⽬录分隔符 String类型
        System.out.println(File.separatorChar);//获取⼀个⽬录分隔符 char类型
        System.out.println(File.pathSeparator);//获取⼀个路径分隔符 String类型
        System.out.println(File.pathSeparatorChar);//获取⼀个路径分隔符 char类型
    }

在这里插入图片描述


四、File类

1.file类的简介

File是 java.io 包中的⼀个类。 是对磁盘上的某⼀个文件、文件夹(目录)的描述。 所谓的⽂件操作, 其实都是需要使用这个类来完成的。

2.file类的构造方法

public static void main(String[] args) {
        /**
         * File类的构造方法
         */
        //构造方法1 通过⼀个路径字符串, 描述⼀个指定路径下的⽂件。
        File file1 = new File("C:\\Users\\Administrator\\Desktop\\text.txt");

        //构造方法2 将parent和child拼接到⼀起, 成⼀个新的路径。
        File file2 = new File("C:\\Users\\Administrator\\Desktop","text.txt");

        //构造方法3 文件夹也可以是一个File类的实例化对象 将parent所描述的路径与child拼接到⼀起,成⼀个新路径。
        File director = new File("C:\\Users\\Administrator\\Desktop");
        File file3 = new File(director, "text.txt");
    }

3.file类的一些常用方法

1、对文件属性的一些操作

public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\Administrator\\Desktop\\test.txt");
        //返回值均为boolean
        System.out.println(file.exists());//判断一个目录文件是否存在
        System.out.println(file.isFile());//判断一个路径指定的是否是一个文件
        System.out.println(file.isDirectory());//判断一个路径指定的是否是一个文件
        System.out.println(file.canExecute());//判断一个文件是否是可执行的
        System.out.println(file.canRead());//判断一个文件是否是可读的
        System.out.println(file.canWrite());//判断一个文件是否是可写的
        System.out.println(file.isHidden());//判断一个文件是否是隐藏的

        //返回值均为String
        System.out.println(file.getName());//获取一个文件的目录
        System.out.println(file.getPath());//获取一个文件的路径(相对路径)
        System.out.println(file.getAbsolutePath());//获取一个文件的路径(绝对路径)
        System.out.println(file.getParent());//获取一个文件的父级路径

        //返回值均为long类型
        System.out.println(file.length());//获取一个文件的大小
        System.out.println(file.lastModified());//最后修改的时间

        /**
         * 将获得的最后修改时间时间戳转换为当前时间
         */
        long time = file.lastModified();
        Date date = new Date(time);
        System.out.println(date);
  }

2、对文件的操作

//返回值均为boolean
File file1 = new File("C:\\Users\\Administrator\\Desktop\\test1.txt");
        if(!file1.exists()){
            //不判断直接创建也不会把原先的覆盖掉
            file1.createNewFile();//在指定路径下创建一个文件
        }
        file1.mkdir();//在指定路径下创建一级文件夹
        file1.mkdirs();//在指定路径下创建多级文件夹
        file1.delete();//删除指定文件 回收站也找不到 慎用
        file1.renameTo(Filedst); //将一个文件重命名为指定的文件 也可以实现文件的移动

3、子文件的获取

File director = new File("C:\\Users\\Administrator\\Desktop");
        director.list();//获取一个目录下所有子文件的名字 返回值为String[]
        director.listFiles();//获取一个目录下所有的子文件 返回值为File[]

五、字节流操作

字节流操作其实就是建立了程序与文件之间连接的管道, 实现数据在这个管道之内进行流动。

管道分为不同的型: 字节输⼊流、 字节输出流、 字符输⼊流、 字符输出流。

1.字节输入流InputStream

这是⼀个字节输⼊流。 从方向来说, 是一个输入流, 数据是从⽂件中流动到程序中,用来读取⽂件中的数据。从数据单位来说, 这个流中流动的数据直接是字节的形式。

public static void main(String[] args) {
        //InputStream --> 输入流  FileInputStream -->  字节流
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\test.txt");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fileInputStream!=null){
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

try/catch
在try结构外面, 声明流对象, 为了在finally中使⽤。
在try结构里面, 实例化流对象, 并捕获异常。
finally结构中, 对流进行关闭。 在关闭的时候, 需要考虑流对象是否是null, 以及要处理IOException 异常。

上面的方式也可以简写,如下:

public static void main(String[] args) {
        try(InputStream fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\text.txt")) {
        }catch (Exception e){
            e.printStackTrace();
        }
    }

当把new FileInputStream放在try中实现后,无需考虑使用完关流的问题,系统会自动关流。
jdk1.7版本以后支持该语法。

2.文件的读取

1、 read()
⼀个一个字节的读,每次读出⼀个字节

public static void main(String[] args) {
        try(InputStream fileInputStream = new FileInputStream("test.txt");) {
            /**
             * read() 读出一个字节
             */
            int read = fileInputStream.read();
            System.out.println((char)read);//读完即打印-1

            /**
             * 使用循环的方式获取字节流
             */
            int a ;//用于接收fileInputStream.read()返回对应字符的ASCII码
            while((a = fileInputStream.read()) != -1){
                System.out.println((char)a);//将a强转为char类型输出
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

2、read(数组)
⼀次可以读出多个字节,数组的作用:每次会将读出的字节临时放到这个数组中

test.txt文件中存放的是"abcde"

public static void main(String[] args) {
        try(InputStream fileInputStream = new FileInputStream("test.txt");) {
            //数组长度就是每次传输的字节数
            byte[] bytes = new byte[3];
            
            //这个方法指的是 使用一个数组去承载想要读取的数据
            fileInputStream.read(bytes);

            /**read通过数组读取 读取的个数是返回值
             * int read = fileInputStream.read(bytes);
             * System.out.println(new String(bytes,0,read));
             * 				//此时read=2
             *    打印结果:
             *             //abc
             *             //de 
             */

            //循环获取
            int num;//用num来存放每次传输的个数 防止最后一次不是3的整数倍从而导致数据重复
            while ((num = fileInputStream.read(bytes)) !=-1){
                System.out.println(new String(bytes, 0, num));
            }

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

3、available()
可以通过available()方法获取全部字节个数

int num = inputStream.available();
byte[] bytes = new byte[num];
 	inputStream.read(bytes);
 	System.out.println(new String(bytes));

3.字节输出流OutputStream

1、使用write()方法写入字节

public static void main(String[] args) {
        // 追加true则会继续往文件中添加数据 不加true则会覆盖内容
        try(FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\text.txt",true)) {
            String str = "Hello World";
            byte[] bytes = str.getBytes();
            
            //outputStream每次写入一个字节
            for (byte b: bytes) {
                outputStream.write(b);
            }
            outputStream.write('\n');//换行
        }catch (Exception e){
            e.printStackTrace();
        }
    }

4.(案例)文件的拷贝

将路径下text.txt文件中的数据拷贝至a.txt中

public static void main(String[] args) {
        try(FileInputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\text.txt");
            FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\a.txt")) {
            byte[] arr = new byte[3];
            int num;
            while((num = inputStream.read(arr)) != -1){
                outputStream.write(arr,0,num);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

同样的也可以使用相同的方法进行图片的的拷贝:

public static void main(String[] args) {
        try(FileInputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\aaa.jpg");
            FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\bbb.jpg")) {
            byte[] arr = new byte[3];
            int num;
            while((num = inputStream.read(arr)) != -1){
                outputStream.write(arr,0,num);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

五、字符流操作

与字节流相对应,对于字符的处理需要用到字符流操作

1.字符输入流Writer

这是一个字符输出流。
从方向上来说, 是⼀个输出流, 数据从程序中流动到文件中,用来实现文件的写操作。

public static void main(String[] args) {
        try(FileWriter writer = new FileWriter("C:\\Users\\Administrator\\Desktop\\a.txt")) {

            String str = "aaaabbbbb";
            char[] arr = str.toCharArray();
            for (char b:arr
                 ) {
                writer.write(b);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2.字符输出流Reader

这是⼀个字符输入流。
从方向来说, 是⼀个输入流, 数据是从文件中流动到程序中, 用来读取文件中的数据。

public static void main(String[] args) {
        try(FileReader reader = new FileReader("C:\\Users\\Administrator\\Desktop\\a.txt")) {

            char[] arr = new char[8];
            int num;
            while((num = reader.read(arr)) != -1){
                String s = new String(arr,0,num);
                System.out.println(s);
            }

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

可以发现,字符流的读写操作和字节流的十分的相似。
掌握字节流的输入输出就可以掌握字符流的。


总结

1、字节流适用于所有情况,可以用于文字、图片、视频等。字符流适用于文字。
2、尝试使用字符流去拷贝图片,发现可以拷贝,但是打不开,拷贝失败。
3、从数据单位来说, 字节流中流动的数据以字节为单位的,不同的是在传输过程中加⼊了编码的操作,让我们的操作更⽅便。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值