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中流的划分

按照方向划分:

输入流:从各种输入设备(磁盘、网卡、键盘...)将数据读取到当前程序

输出流:从当前程序将数据写入输出设备(磁盘、网卡、屏幕)

按照数据传输单元划分:

字节流:以字节(byte)为单位的数据传输流, InputStream和OutputStream

字符流:以字符(char)为单位的数据传输流,Reader、Writer

按照功能划分:

节点流:用于直接操作目标设备的流

过滤流(高级流):对一个已存在的流进行包装,以提供更强大灵活的读写功能

File类介绍

File类主要是对文件或者目录的抽象表示

文件可以理解为保存数据的一种方式

文件一共有两部分组成,属性(文件名、大小、类型)和内容(文件中存储的内容)

File类的构造函数

构造函数

File (String pathName)

通过路径字符串获取file实例

File(String parent, String child)

第一个参数:父路径字符串 第二个参数:文件名字符串

File(File parent, String child)

第一个参数:父路径File对象 第二个参数:文件名字符串

调用示例

        String path="E:\\java\\IO\\test1.txt";

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

        String parentPathName="E:\\java\\IO";
        String name="test1.txt";
        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

ava中File类中有静态属性separator表示路径分隔符

public static final String separator = "" + separatorCha

基础方法:

       String parentPathName = "E:\\java\\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]);
        }
    }

搜索功能代码:

 /**
     * 给定指定路径名,进行搜索
     * @param args
     */
    public static void main(String[] args) {
            String path="E:\\java\\IO";
            String filter="1";
            searchFile(path,filter);
        }
        public static void searchFile(String path,String filter){
            File file=new File(path);
            if(!file.exists()){
                //当前文件不存在
                System.out.println("非法路径");
            }
            if(file.isFile()){
                //当前是文件
                if(file.getName().contains(filter)){
                    System.out.println(file.getPath());
                    /**
                     * 如果传递的路径参数是绝对路径(文件或者目录)
                     * getPath和getAbsolutePath是一致的,都是绝对路径
                     *
                     * 如果传递的路径参数是相对路径
                     * getPath拿到的是指定的参数路径名,getAbsolutePath拿到的是绝对路径名
                     */
                }
            }
            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);
                }
            }
        }

树形打印:

/**
     * 树形结构打印
     * 思路:
     *     在打印文件时,考虑当前文件或目录相对给定的目录的层级
     *     每加深一层,多添加一个“-”操作
     *     考虑目录的层级问题,使用递归
     */
    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+="-";
        }
        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);
            }
        }
    }

    public static void main(String[] args) {
        String path="E:\\java\\IO";
        printTree(path);
    }

猜你喜欢

转载自blog.csdn.net/iiiiiiiiiooooo/article/details/121108296
今日推荐