IO流介绍

输入流、输出流
介质流、高级流
字节流、字符流
4个基类:InputStream,OutputStream、Reader和writer
FileXXX、BufferedXXX、ObjectXXX
序列化和反序列化概念、以ArrayList为例介绍序列化和反序列化的实现
IO流中涉及的设计模式:适配器和装饰器模式
File文件操作类
RandomAccessFile类
java8新特征:labada表达式、流式编程

基础概念

在介绍IO流原理之前,先重温几个基础概念

操作系统与内核

在这里插入图片描述
**操作系统:**管理计算机硬件与软件资源的系统软件
**内核:**操作系统的核心软件,负责管理系统的进程、内存、设备驱动程序、文件和网络系统等等,为应用程序提供对计算机硬件的安全访问服务

内核空间和用户空间

为了避免用户进程直接操作内核,保证内核安全,操作系统将内存寻址空间划分为两部分:
内核空间(Kernel-space),供内核程序使用,有最高权限,可以直接访问所有资源
用户空间(User-space),供用户进程使用,只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。
为了安全,内核空间和用户空间是隔离的,即使用户的程序崩溃了,内核也不受影响。
在这里插入图片描述
系统调用是操作系统的最小功能单位,通过提供一些基本功能的接口供应用程序调用来调度内核空间管理的资源
当程序运行从用户态切换到内核态,那么处在用户态的进程需要先保存当前的数据以及运行的指令,方便回到用户态时继续执行,这中间还有很多其他的事情需要做,例如CPU寄存器需要保存和加载, 系统调度器的代码需要执行等。

数据流

在这里插入图片描述
计算机中的数据是基于随着时间变换高低电压信号传输的,这些数据信号连续不断,有着固定的传输方向,类似水管中水的流动,因此抽象数据流(I/O流)的概念:指一组有顺序的、有起点和终点的字节集合,
抽象出数据流的作用:实现程序逻辑与底层硬件解耦,通过引入数据流作为程序与硬件设备之间的抽象层,面向通用的数据流输入输出接口编程,而不是具体硬件特性,程序和底层硬件可以独立灵活替换和扩展。
在这里插入图片描述

IO工作原理

磁盘IO
典型I/O读写磁盘工作原理如下:
在这里插入图片描述
CPU复制
在 DMA 技术出现之前,应用程序与磁盘之间的 I/O 操作都是通过 CPU 的中断完成的。每次用户进程读取磁盘数据时,都需要 CPU 中断将数据读进暂存器,然后发起 I/O 请求等待数据读取和拷贝完成,然后写进其它地方,每次的 I/O 中断都导致 CPU 的上下文切换。
DMA复制
DMA(Direct Memory Access,直接存储器访问) ,基于 DMA 访问方式,系统主内存与硬件设备的数据传输可以省去CPU 的全程调度
具体流程:CPU对DMA控制器初始化,向I/O接口发出操作命令,I/O接口提出DMA请求。DMA控制器对DMA请求判别优先级及评比,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。
值得注意的是:
● 读写操作基于系统调用实现
● 读写操作经过用户缓冲区,内核缓冲区,应用进程并不能直接操作磁盘
● 应用进程读操作时需阻塞直到读取到数据
网络I/O
这里以经典的阻塞式I/O模型介绍:
在这里插入图片描述
在这里插入图片描述
值得注意的是:
● 网络I/O读写操作经过用户缓冲区,Sokcet缓冲区
● 服务端线程在从调用开始到它返回有数据报准备好这段时间是阻塞的,read返回成功后,线程开始处理数据报

Java IO流设计

流介绍
Java中所有的数据都是使用流读写的,流是一组有顺序、有方向,有起点和重点的字节集合,是对数据传输的总称
流体系:
在这里插入图片描述
流的实现类:
在这里插入图片描述

Java中流的划分

按照方向划分:
输入流:从各种输入设备(磁盘、网卡、键盘…)将数据读取到当前程序
输出流:从当前程序将数据写入输出设备(磁盘、网卡、屏幕)
在这里插入图片描述
按照数据传输单元划分:
字节流:以字节为单位的数据传输流, InputStream和OutputStream
字符流:以字符为单位的数据传输流,Reader、Writer

按照功能划分:
节点流:用于直接操作目标设备的流
过滤流(高级流):对一个已存在的流进行包装,以提供更强大灵活的读写功能
在这里插入图片描述

File类介绍

File类主要是对文件或者目录的抽象表示
文件可以理解为保存数据的一种方式
文件一共有两部分组成,属性(文件名、大小、类型)和内容(文件中存储的内容)

File类的构造函数
在这里插入图片描述
调用示例:

        String path = "/Users/gongdezhe/Desktop/IO/test1.txt";

        //通过一个字符串路径创建file实例
        File file = new File(path);


        String parentPathName = "/Users/gongdezhe/Desktop/IO";
        String name = "test1.txt";
        //通过父路径字符串和文件名字符串创建file实例
        File file1 = new File(parentPathName, name);


        File parentFileName = new File(parentPathName);
        //通过父路径的file对象和文件名字符串创建file实例
        File file2 = new File(parentFileName, name);

绝对路径和相对路径
绝对路径:带盘符开始的路径, 比如:windows系统:C:\ Linux: /
相对路径:不带盘符的路径 '.'当前路径 ‘…’:父路径

路径分割符:
Linux:‘/’ 例如:/Users/gongdezhe/Desktop/IO/test1.txt
Windows系统:‘\’ 例如:C:\test\test1.text

public static final String separator = "" + separatorChar

使用示例:

String s = “User”+File.separator+“keke”+File.separator+“Desktop”;

基础方法

        String parentPathName = "/Users/keke/Desktop/IO";
        File file = new File(parentPathName);
//        try {
            /**
             * boolean createNewFile()
             * 创建新的文件
             * 返回值:true 表示创建成功  false:创建不成功
             * 当文件已经存在则返回false
             * 另:创建文件的路径必须是存在的,如果父路径有不存在的则抛异常
             */
//            file.createNewFile();
            //可能会抛出异常
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        /**
         * boolean delete()
         * 删除文件
         * true:表示删除成功  false:表示删除失败  文件不存在返回false
         */
//        file.delete();


        /**
         * boolean exists()
         * 判断文件是否存在
         * 存在则返回true,不存在则返回false
         */
        file.exists();

        /**
         * boolean isFile()
         * 判断当前file实例是否为文件 true:为文件
         */
        file.isFile();

        /**
         * boolean isDirectory()
         * 判断当前file实例是否为目录 true:表示是目录
         */
        file.isDirectory();


        /**
         * boolean isHidden()
         * 判断当前file实例是否为隐藏文件 true:为隐藏文件
         */
        file.isHidden();

//        System.out.println(file.isHidden());


        /**
         * boolean mkdir()
         * 创建目录 ,只适用于创建单个目录
         * true:创建成功,false:创建失败
         */
        file.mkdir();

        /**
         * boolean mkdirs()
         * 创建目录  可以创建多级目录
         */
        file.mkdirs();


        /**
         *  String getPath()
         *  获取路径字符串实例
         */
        String path = file.getPath();


        /**
         * String getParent()
         * 获取父路径字符串
         */
        String parent = file.getParent();
//        System.out.println(path);
//        System.out.println(parent);


        /**
         * String getAbsolutePath()
         * 获取绝对路径
         */
        file.getAbsolutePath();

        /**
         * String getName()
         * 获取文件或目录名称
         */
        file.getName();

        /**
         * long length()
         * 返回文件的字节数,目录则返回是0
         */
        file.length();


        /**
         * String[] list()
         *返回的是当前目录的所有子文件或目录
         * File[] listFiles()
         * 返回的是当前目录的所有子文件或目录的file实例
         */
        String[] list = file.list();

        File[] files = file.listFiles();


        /**
         * String[] list(FilenameFilter filter)
         * 将目录结果过滤将符合要求的返回
         *
         * FilenameFilter接口,
         * 接口中存在accept(File dir, String name)方法
         * 第一个参数:表示是父路径的file实例
         * 第二个参数:表示当前文件或目录名称
         */
        String[] list1 = file.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return !(new File(dir,name).isHidden());
            }
        });
        for (int i = 0; i < list1.length; i++) {
            System.out.println(list1[i]);
        }
    }

搜索功能代码:

public static void searchFile(String path, String filter) {
    File file = new File(path);
    if (!file.exists()) {
        System.out.println("非法路径");
        return;
    }

    if (file.isFile()) {
        //当前是文件
        if (file.getName().contains(filter)) {
            System.out.println(file.getPath());
        }
    }
    if (file.isDirectory()) {
        //当前是目录
        searchDir(file,filter);
    }


}


/**
 * 通过目录查询关键字
 */
private static void searchDir(File file,String filter) {
    //返回当前目录下的所有文件及子目录
    File[] files = file.listFiles();
    for (int i = 0; i < files.length; i++) {
        File file1 = files[i];
        if (file1.isFile()) {
            if (file1.getName().contains(filter)) {
                //当前目录是符合条件的打印
                System.out.println(file1.getPath());
            }
        } else {
            //当前是目录
            searchDir(file1,filter);
        }
    }
}

树形打印

/**
     * 树形结构打印
     * @param filePath
     * | IO
     * |-test1.txt
     * |-test2.txt
     * |-test3.txt
     * |-test3.txt
     * |-IO3
     * |--test11.txt
     * |--IO33
     * |---test.txt
     *
     *  思路:
     *  在打印文件时,考虑当前文件或目录相对给定的目录的层级
     *  没加深一层,多添加一个"-"操作
     *  考虑目录层级问题,使用递归
     *
     */
    public static void printTree(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            System.out.println("指定路径不存在");
        }
        if (file.isFile()) {
            System.out.println("|"+file.getName());
        } else {
            //是目录
            System.out.println("|"+file.getName());
            printDir(file,0);
        }

    }

    /**
     *
     * @param file  目录的file实例
     * @param dept  表示当前的深度
     */
    private static void printDir(File file, int dept) {
        String pre = "|";
        for (int i = 0; i <= dept; i++) {
            pre+="- ";
        }
//        System.out.println(pre+file.getName());
        //当前目录的子文件及目录
        File[] files = file.listFiles();
        for (int i = 0; i < files.length; i++) {
            File file1 = files[i];
            System.out.println(pre+file1.getName());
            if (file1.isDirectory()) {
                printDir(file1,dept+1);
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值