小师妹学IO系列文章集合-附PDF下载(一)

简介: 小师妹学IO系列文章集合-附PDF下载(一)

目录



java中最最让人激动的部分就是IO和NIO了。IO的全称是input output,是java程序跟外部世界交流的桥梁,IO指的是java.io包中的所有类,他们是从java1.0开始就存在的。NIO叫做new IO,是在java1.4中引入的新一代IO。


IO的本质是什么呢?它和NIO有什么区别呢?我们该怎么学习IO和NIO呢?


本系列将会借助小师妹的视角,详细讲述学习java IO的过程,希望大家能够喜欢。


小师妹何许人也?姓名不详,但是勤奋爱学,潜力无限,一起来看看吧。


本文的例子https://github.com/ddean2009/learn-java-io-nio


文章太长,大家可以直接下载本文PDF:下载链接java-io-all-in-one.pdf


第一章 IO的本质


IO的本质


IO的作用就是从外部系统读取数据到java程序中,或者把java程序中输出的数据写回到外部系统。这里的外部系统可能是磁盘,网络流等等。


因为对所有的外部数据的处理都是由操作系统内核来实现的,对于java应用程序来说,只是调用操作系统中相应的接口方法,从而和外部数据进行交互。


所有IO的本质就是对Buffer的处理,我们把数据放入Buffer供系统写入外部数据,或者从系统Buffer中读取从外部系统中读取的数据。如下图所示:


image.png

用户空间也就是我们自己的java程序有一个Buffer,系统空间也有一个buffer。所以会出现系统空间缓存数据的情况,这种情况下系统空间将会直接返回Buffer中的数据,提升读取速度。


DMA和虚拟地址空间


在继续讲解之前,我们先讲解两个操作系统中的基本概念,方便后面我们对IO的理解。


现代操作系统都有一个叫做DMA(Direct memory access)的组件。这个组件是做什么的呢?


一般来说对内存的读写都是要交给CPU来完成的,在没有DMA的情况下,如果程序进行IO操作,那么所有的CPU时间都会被占用,CPU没法去响应其他的任务,只能等待IO执行完成。这在现代应用程序中是无法想象的。


如果使用DMA,则CPU可以把IO操作转交给其他的操作系统组件,比如数据管理器来操作,只有当数据管理器操作完毕之后,才会通知CPU该IO操作完成。现代操作系统基本上都实现了DMA。


虚拟地址空间也叫做(Virtual address space),为了不同程序的互相隔离和保证程序中地址的确定性,现代计算机系统引入了虚拟地址空间的概念。简单点讲可以看做是跟实际物理地址的映射,通过使用分段或者分页的技术,将实际的物理地址映射到虚拟地址空间。


image.png


对于上面的IO的基本流程图中,我们可以将系统空间的buffer和用户空间的buffer同时映射到虚拟地址空间的同一个地方。这样就省略了从系统空间拷贝到用户空间的步骤。速度会更快。


同时为了解决虚拟空间比物理内存空间大的问题,现代计算机技术一般都是用了分页技术。


分页技术就是将虚拟空间分为很多个page,只有在需要用到的时候才为该page分配到物理内存的映射,这样物理内存实际上可以看做虚拟空间地址的缓存。


虚拟空间地址分页对IO的影响就在于,IO的操作也是基于page来的。


比较常用的page大小有:1,024, 2,048, 和 4,096 bytes。


IO的分类


IO可以分为File/Block IO和Stream I/O两类。


对于File/Block IO来说,数据是存储在disk中,而disk是由filesystem来进行管理的。我们可以通过filesystem来定义file的名字,路径,文件属性等内容。


filesystem通过把数据划分成为一个个的data blocks来进行管理。有些blocks存储着文件的元数据,有些block存储着真正的数据。


最后filesystem在处理数据的过程中,也进行了分页。filesystem的分页大小可以跟内存分页的大小一致,或者是它的倍数,比如 2,048 或者 8,192 bytes等。


并不是所有的数据都是以block的形式存在的,我们还有一类IO叫做stream IO。


stream IO就像是管道流,里面的数据是序列被消费的。


IO和NIO的区别


java1.0中的IO是流式IO,它只能一个字节一个字节的处理数据,所以IO也叫做Stream IO。


而NIO是为了提升IO的效率而生的,它是以Block的方式来读取数据的。


Stream IO中,input输入一个字节,output就输出一个字节,因为是Stream,所以可以加上过滤器或者过滤器链,可以想想一下web框架中的filter chain。在Stream IO中,数据只能处理一次,你不能在Stream中回退数据。


在Block IO中,数据是以block的形式来被处理的,因此其处理速度要比Stream IO快,同时可以回退处理数据。但是你需要自己处理buffer,所以复杂程度要比Stream IO高。


一般来说Stream IO是阻塞型IO,当线程进行读或者写操作的时候,线程会被阻塞。


而NIO一般来说是非阻塞的,也就是说在进行读或者写的过程中可以去做其他的操作,而读或者写操作执行完毕之后会通知NIO操作的完成。


在IO中,主要分为DataOutPut和DataInput,分别对应IO的out和in。


DataOutPut有三大类,分别是Writer,OutputStream和ObjectOutput。


看下他们中的继承关系:



image.png


DataInput也有三大类,分别是ObjectInput,InputStream和Reader。


看看他们的继承关系:


image.png


image.png

NIO需要掌握的类的个数比IO要稍稍多一点,毕竟NIO要复杂一点。


就这么几十个类,我们就掌握了IO和NIO,想想都觉得兴奋。


总结


后面的文章中,我们会介绍小师妹给你们认识,刚好她也在学java IO,后面的学习就跟她一起进行吧,敬请期待。


第二章 try with和它的底层原理


简介


小师妹是个java初学者,最近正在学习使用java IO,作为大师兄的我自然要给她最给力的支持了。一起来看看她都遇到了什么问题和问题是怎么被解决的吧。


IO关闭的问题


这一天,小师妹一脸郁闷的问我:F师兄,我学Java IO也有好多天了,最近写了一个例子,读取一个文件没有问题,但是读取很多个文件就会告诉我:”Can't open so many files“,能帮我看看是什么问题吗?


更多内容请访问www.flydean.com


小师妹的要求当然不能拒绝,我立马响应:可能打开文件太多了吧,教你两个命令,查看最大文件打开限制。


一个命令是 ulimit -a


image.png


第二个命令是


ulimit -n
256

看起来是你的最大文件限制太小了,只有256个,调大一点就可以了。


小师妹却说:不对呀F师兄,我读文件都是一个一个读的,没有同时开这么多文件哟。


好吧,看下你写的代码吧:


BufferedReader bufferedReader = null;
        try {
            String line;
            bufferedReader = new BufferedReader(new FileReader("trywith/src/main/resources/www.flydean.com"));
            while ((line = bufferedReader.readLine()) != null) {
                log.info(line);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }


看完代码,问题找到了,小师妹,你的IO没有关闭,应该在使用之后,在finally里面把你的reader关闭。


下面这段代码就行了:


BufferedReader bufferedReader = null;
        try {
            String line;
            bufferedReader = new BufferedReader(new FileReader("trywith/src/main/resources/www.flydean.com"));
            while ((line = bufferedReader.readLine()) != null) {
                log.info(line);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (bufferedReader != null){
                 bufferedReader.close();
                }
            } catch (IOException ex) {
                log.error(ex.getMessage(), ex);
            }
        }


小师妹道了一声谢,默默的去改代码了。


使用try with resource


过了半个小时 ,小师妹又来找我了,F师兄,现在每段代码都要手动添加finally,实在是太麻烦了,很多时候我又怕忘记关闭IO了,导致程序出现无法预料的异常。你也知道我这人从来就怕麻烦,有没有什么简单的办法,可以解决这个问题呢?


那么小师妹你用的JDK版本是多少?


小师妹不好意思的说:虽然最新的JDK已经到14了,我还是用的JDK8.JDK8就够了,其实从JDK7开始,Java引入了try with resource的新功能,你把使用过后要关闭的resource放到try里面,JVM会帮你自动close的,是不是很方便,来看下面这段代码:


try (BufferedReader br = new BufferedReader(new FileReader("trywith/src/main/resources/www.flydean.com")))
        {
            String sCurrentLine;
            while ((sCurrentLine = br.readLine()) != null)
            {
                log.info(sCurrentLine);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }


try with resource的原理


太棒了,小师妹非常开心,然后又开始问我了:F师兄,什么是resource呀?为什么放到try里面就可以不用自己close了?


resource就是资源,可以打开个关闭,我们可以把实现了java.lang.AutoCloseable接口的类都叫做resource。


先看下AutoCloseable的定义:


public interface AutoCloseable {
        void close() throws Exception;
}


AutoCloseable定义了一个close()方法,当我们在try with resource中打开了AutoCloseable的资源,那么当try block执行结束的时候,JVM会自动调用这个close()方法来关闭资源。


我们看下上面的BufferedReader中close方法是怎么实现的:


public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        in.close();
        in = null;
        cb = null;
    }
}


自定义resource


小师妹恍然大悟:F师兄,那么我们是不是可以实现AutoCloseable来创建自己的resource呢?


当然可以了,我们举个例子,比如给你解答完这个问题,我就要去吃饭了,我们定义这样一个resource类:


public class CustResource implements AutoCloseable {
    public void helpSister(){
        log.info("帮助小师妹解决问题!");
    }
    @Override
    public void close() throws Exception {
        log.info("解决完问题,赶紧去吃饭!");
    }
    public static void main(String[] args) throws Exception {
       try( CustResource custResource= new CustResource()){
           custResource.helpSister();
       }
    }
}


运行输出结果:


[main] INFO com.flydean.CustResource - 帮助小师妹解决问题!
[main] INFO com.flydean.CustResource - 解决完问题,赶紧去吃饭!


总结


最后,小师妹的问题解决了,我也可以按时吃饭了。


第三章 File文件系统


简介


小师妹又遇到难题了,这次的问题是有关文件的创建,文件权限和文件系统相关的问题,还好这些问题的答案都在我的脑子里面,一起来看看吧。


文件权限和文件系统


早上刚到公司,小师妹就凑过来神神秘秘的问我:F师兄,我在服务器上面放了一些重要的文件,是非常非常重要的那种,有没有什么办法给它加个保护,还兼顾一点隐私?


更多内容请访问www.flydean.com


什么文件这么重要呀?不会是你的照片吧,放心没人会感兴趣的。


小师妹说:当然不是,我要把我的学习心得放上去,但是F师兄你知道的,我刚刚开始学习,很多想法都不太成熟,想先保个密,后面再公开。


看到小师妹这么有上进心,我老泪纵横,心里很是安慰。那就开始吧。


你知道,这个世界上操作系统分为两类,windows和linux(unix)系统。两个系统是有很大区别的,但两个系统都有一个文件的概念,当然linux中文件的范围更加广泛,几乎所有的资源都可以看做是文件。


有文件就有对应的文件系统,这些文件系统是由系统内核支持的,并不需要我们在java程序中重复造轮子,直接调用系统的内核接口就可以了。


小师妹:F师兄,这个我懂,我们不重复造轮子,我们只是轮子的搬运工。那么java是怎么调用系统内核来创建文件的呢?


创建文件最常用的方法就是调用File类中的createNewFile方法,我们看下这个方法的实现:


public boolean createNewFile() throws IOException {
        SecurityManager security = System.getSecurityManager();
        if (security != null) security.checkWrite(path);
        if (isInvalid()) {
            throw new IOException("Invalid file path");
        }
        return fs.createFileExclusively(path);
    }


方法内部先进行了安全性检测,如果通过了安全性检测就会调用FileSystem的createFileExclusively方法来创建文件。


在我的mac环境中,FileSystem的实现类是UnixFileSystem:


public native boolean createFileExclusively(String path)
        throws IOException;


看到了吗?UnixFileSystem中的createFileExclusively是一个native方法,它会去调用底层的系统接口。


小师妹:哇,文件创建好了,我们就可以给文件赋权限了,但是windows和linux的权限是一样的吗?


这个问题问得好,java代码是跨平台的,我们的代码需要同时在windows和linux上的JVM执行,所以必须找到他们权限的共同点。


我们先看一下windows文件的权限:


image.png


可以看到一个windows文件的权限可以有修改,读取和执行三种,特殊权限我们先不用考虑,因为我们需要找到windows和linux的共同点。


再看下linux文件的权限:


ls -al www.flydean.com 
-rw-r--r--  1 flydean  staff  15 May 14 15:43 www.flydean.com


上面我使用了一个ll命令列出了www.flydean.com这个文件的详细信息。 其中第一列就是文件的权限了。


linux的基本文件权限可以分为三部分,分别是owner,group,others,每部分和windows一样都有读,写和执行的权限,分别用rwx来表示。


三部分的权限连起来就成了rwxrwxrwx,对比上面我们的输出结果,我们可以看到www.flydean.com这个文件对owner自己是可读写的,对Group用户是只读的,对other用户也是只读的。


你要想把文件只对自己可读,那么可以执行下面的命令:


chmod 600 www.flydean.com


小师妹立马激动起来:F师兄,这个我懂,6用二进制表示就是110,600用二进制表示就是110000000,刚刚好对应rw-------。


对于小师妹的领悟能力,我感到非常满意。


文件的创建


虽然我们已经不是孔乙己时代了,不需要知道茴字的四种写法,但是多一条知识多一条路,做些充足的准备还是非常有必要的。


小师妹,那你知道在java中有哪几种文件的创建方法呢?


小师妹小声道:F师兄,我只知道一种new File的方法。


我满意的抚摸着我的胡子,显示一下自己高人的气场。


之前我们讲过了,IO有三大类,一种是Reader/Writer,一种是InputStream/OutputStream,最后一种是ObjectReader/ObjectWriter。


除了使用第一种new File之外,我们还可以使用OutputStream来实现,当然我们还要用到之前讲到try with resource特性,让代码更加简洁。


先看第一种方式:


public void createFileWithFile() throws IOException {
        File file = new File("file/src/main/resources/www.flydean.com");
        //Create the file
        if (file.createNewFile()){
            log.info("恭喜,文件创建成功");
        }else{
            log.info("不好意思,文件创建失败");
        }
        //Write Content
        try(FileWriter writer = new FileWriter(file)){
            writer.write("www.flydean.com");
        }
    }


再看第二种方式:


public  void createFileWithStream() throws IOException
    {
        String data = "www.flydean.com";
        try(FileOutputStream out = new FileOutputStream("file/src/main/resources/www.flydean.com")){
            out.write(data.getBytes());
        }
    }


第二种方式看起来比第一种方式更加简介。


小师妹:慢着,F师兄,JDK7中NIO就已经出现了,能不能使用NIO来创建文件呢?


这个问题当然难不到我:


public void createFileWithNIO()  throws IOException
    {
        String data = "www.flydean.com";
        Files.write(Paths.get("file/src/main/resources/www.flydean.com"), data.getBytes());
        List<String> lines = Arrays.asList("程序那些事", "www.flydean.com");
        Files.write(Paths.get("file/src/main/resources/www.flydean.com"),
                lines,
                StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.APPEND);
    }


NIO中提供了Files工具类来实现对文件的写操作,写的时候我们还可以带点参数,比如字符编码,是替换文件还是在append到文件后面等等。


代码中文件的权限


小师妹又有问题了:F师兄,讲了半天,还没有给我讲权限的事情啦。


别急,现在就讲权限:


public void fileWithPromission() throws IOException {
        File file = File.createTempFile("file/src/main/resources/www.flydean.com","");
        log.info("{}",file.exists());
        file.setExecutable(true);
        file.setReadable(true,true);
        file.setWritable(true);
        log.info("{}",file.canExecute());
        log.info("{}",file.canRead());
        log.info("{}",file.canWrite());
        Path path = Files.createTempFile("file/src/main/resources/www.flydean.com", "");
        log.info("{}",Files.exists(path));
        log.info("{}",Files.isReadable(path));
        log.info("{}",Files.isWritable(path));
        log.info("{}",Files.isExecutable(path));
    }


上面我们讲过了,JVM为了通用,只能取windows和linux都有的功能,那就是说权限只有读写和执行权限,因为windows里面也可以区分本用户或者其他用户,所以是否是本用户的权限也保留了。


上面的例子我们使用了传统的File和NIO中的Files来更新文件的权限。


总结


好了,文件的权限就先讲到这里了。



相关文章
|
16天前
|
机器学习/深度学习 分布式计算 算法
Spark快速大数据分析PDF下载读书分享推荐
《Spark快速大数据分析》适合初学者,聚焦Spark实用技巧,同时深入核心概念。作者团队来自Databricks,书中详述Spark 3.0新特性,结合机器学习展示大数据分析。Spark是大数据分析的首选工具,本书助你驾驭这一利器。[PDF下载链接][1]。 ![Spark Book Cover][2] [1]: https://zhangfeidezhu.com/?p=345 [2]: https://i-blog.csdnimg.cn/direct/6b851489ad1944548602766ea9d62136.png#pic_center
42 1
Spark快速大数据分析PDF下载读书分享推荐
|
12天前
|
安全 算法 文件存储
共享资料下载,自动转PDF并添加隐形水印
云盒子企业网盘增强文件安全,支持下载时自动转PDF并加水印。管理员可配置目录规则,选择明水印、隐形水印或点阵水印。明水印直观防复制,隐形水印用于隐蔽追踪,点阵水印不影响阅读。文件格式支持度和水印类型取决于设置。此功能适用于文档安全、版权保护等场景。欲知详情或测试,访问[云盒子官网](yhz66.com)咨询客服。
|
9天前
|
JavaScript 前端开发 程序员
《JavaScript权威指南第7版》中文PDF+英文PDF+源代码 +JavaScript权威指南(第6版)(附源码)PDF下载阅读分享推荐
JavaScript是Web标准语言,广泛应用于各类浏览器,造就了其最广泛部署的地位。Node.js的兴起扩展了JavaScript的使用场景,使其成为开发者首选语言。无论新手还是经验丰富的程序员,都能受益于学习JavaScript。[《JavaScript权威指南第7版》资源链接](https://zhangfeidezhu.com/?p=224)
25 5
《JavaScript权威指南第7版》中文PDF+英文PDF+源代码 +JavaScript权威指南(第6版)(附源码)PDF下载阅读分享推荐
|
16天前
|
C++ Python
《从零开始学Python》(第二版) PDF下载读书分享
Python,由Guido van Rossum创造(1989),是1991年发布的面向对象、解释型编程语言,以其简洁清晰的语法和强大的库著称,昵称“胶水语言”。它连接不同模块,强调代码的优雅、明确和简单。《从零开始学Python》(第二版)是本风趣、实践导向的教材,提供PDF下载,是学习Python的宝贵资源。![书封](https://ucc.alicdn.com/pic/developer-ecology/nrw3f3oqlpmag_40f357729aac4defa97fb1e0f66a2501.png)
20 1
《从零开始学Python》(第二版) PDF下载读书分享
|
11天前
ChatGPT提问获取高质量答案的艺术PDF下载书籍推荐分享
**掌握ChatGPT高质量Prompt技巧的指南,教你艺术性提问以获取卓越答案。适用于各层次用户,提升内容创作效率。了解Prompt工程,作为对话模式触发器,有效引导ChatGPT生成人类般文本。点击获取PDF资源:[ChatGPT提问艺术](https://zhangfeidezhu.com/?p=334)**
11 0
ChatGPT提问获取高质量答案的艺术PDF下载书籍推荐分享
|
12天前
ChatGPT提问提示指南PDF下载经典分享推荐书籍,让你做好prompt工程
**掌握ChatGPT提问艺术:本书提供有效互动策略,教你构造精准提示获取专业答案。适用于各层次用户,通过实例解析提示工程,驱动模型生成定制化文本。[PDF下载](https://zhangfeidezhu.com/?p=335)**
29 0
ChatGPT提问提示指南PDF下载经典分享推荐书籍,让你做好prompt工程
|
13天前
|
数据挖掘 Python
利用Python进行数据分析PDF下载经典数据分享推荐
**Python数据分析大师作,Wes McKinney亲著,详述数据操作、清洗与分析。第2版面向Python 3.6,涵盖pandas、NumPy、IPython和Jupyter更新,实战案例丰富;第3版已升级至Python 3.10和pandas 1.4,继续引领数据科学潮流。[PDF下载](https://zhangfeidezhu.com/?p=337)**
20 0
利用Python进行数据分析PDF下载经典数据分享推荐
|
25天前
|
网络协议
一篇文章讲明白IO流实现写入规定的acci码值
一篇文章讲明白IO流实现写入规定的acci码值
|
2月前
|
Python
小白入门必备!计科教授的Python精要参考PDF开放下载!
随着互联网产业的高速发展,在网络上早已积累了极其丰富的Python学习资料,任何人都可以基于这些资源,自学掌握 Python。 但实际上,网络上充斥的资源太多、太杂且不成体系,在没有足够的编程/工程经验之前,仅靠“看”线上资源自学,的确是一件非常困难的事。
|
2月前
|
消息中间件 关系型数据库 Kafka
实时计算 Flink版操作报错之在执行任务时遇到了一个IO错误,具体表现为无法从本地主机(localhost)下载文件,该怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。

热门文章

最新文章