文章目录

  • 一.操作系统与内核
    • 1.1操作系统
    • 1.2内核
    • 1.3 关系图
  • 二、内核空间和用户空间
    • 2.1:目的:
    • 2.2、内核空间(Kernel-space):
    • 2.3、用户空间(User-space):
    • 2.4、内核空间与用户空间通讯
    • 2.5、用户态和内核态的区别
    • 2.6、用户态转换为内核态的3种方式
      • 2.6.1、系统调用
      • 2.6.2、异常
      • 2.6.3、外围设备的中断
    • 2.7、系统调用:
  • 三、数据流
  • 四、IO工作原理
    • 4.1、磁盘IO
      • 典型的IO读写磁盘工作原理如下;
    • 4.2、COU复制
    • 4.3、DMA复制
    • 4.4、网络I/O
  • 五、Java I/O流设计
    • 5.1、流介绍
    • 5.2、流体系
    • 5.3、流的实现类
    • 5.4、java中流的划分
    • 5.5、java I/O原理
  • 六、Java I/O系统
    • 6.1、Java标准类库中各种各样的类以及它们的用法
      • 6.1.1 File类
      • 6.1.2 InputStream类型
      • 6.1.3 OutputStream类型
    • 6.2 I/O流的典型使用方式
      • 6.2.1 缓冲输入文件
      • 6.2.2基本的文件输出
      • 6.2.3存储和恢复数据
      • 6.2.4文件读写的使用工具
      • 6.2.5标准I/O
    • 6.3进程控制
    • 6.4 新I/O
    • 6.5 压缩

在介绍IO流之前,先介绍一下一些基础的概念

一.操作系统与内核

1.1操作系统

  1. 俗话说,操作系统是连接系统软硬件的一座桥梁,它自身本质上就是一个软件。
  2. 他的作用就是管理计算机硬件与软件资源的学习通软件。

1.2内核

  • 内核主要是操作系统的核心软件,负责管理系统的进程、内存、设备驱动软件、文件和网络系统等等,为应用程序提供对计算机硬件的安全访问服务。

1.3 关系图

二、内核空间和用户空间

2.1:目的:

  • 为了避免用户进程直接操作内核,保证内核安全,操作系统将内存寻址空间划分为两部分:

2.2、内核空间(Kernel-space):

  • 在Linux中,Linux驱动程序一般工作在内核空间,但也可以工作在用户空间;
  • Linux简化了分段机制,使得虚拟地址与线性地址总线是一致的,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用成为内核空间。而将较低的3G字节(从0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。
  • 因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内所有进程共享,于是,从具体进程角度来看,每个进程可以拥有4G字节的虚拟空间。
  • 内核空间中存放的是内核代码和数据,而进程的使用空间中存放的是用户程序的代码和数据,不管是内核空间还是用户空间,他们都处于虚拟空间中,虽然内核空间占据了每个虚拟内存中最高1GB字节,但映射到物理内存却总是从最低地址(0x00000000)开始。
  • 对内核空间来说,期地址映射事件单的线性映射,0xc0000000就是物理地址和线性地址之间的的位移量,在Linux代码中就叫做PAGE_OFFSET

2.3、用户空间(User-space):

  • 用户空间就是用户进程所在的内存区域,而用户进程和系统进程的所有数据都在内存中,
  • 供用户进程使用,只能访问受限权限,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,只能才能访问这些特殊权限。
  • 为了安全,内核空间和用户空间是隔离的,即使用户空间的程序崩溃了,内核也不受影响。
  • 处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。

2.4、内核空间与用户空间通讯

  • 内核空间和用户空间一般通过系统调用进行通信。

2.5、用户态和内核态的区别

  • 当一个任务(进程)执行系统调用而陷入内核代码执行时,我们就称进程处于内核运行态即内核态。此时处理器处于特权级最高的0级内核中执行;当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈,当进程在执行自己的内核代码时,则称其处于用户运行态即用户态,此时处理器在特权级最低的3级用户代码中运行。
  • 内核态与用户态时操作系统的两种运行级别,Intel x86架构提供Ring0-Ring3四种级别的运行模式,Ring0级别最高,Ring3级别最低。
  • Linux使用了Ring三级别运行用户态,Ring0作为内核态,没有使用Ring1和ring2 .Ring3状态不能访问Ring0的地址空间,包括代码和数据。程序特权级别的不同,所具有的权利也不同

2.6、用户态转换为内核态的3种方式

  • 这三种方式是系统在运行时由用户态转到内核态的最主要的方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。

2.6.1、系统调用

  • 这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务进程完成工作,比如fork()实际上就是执行一个创建新进程的一种系统调用,而系统调用的及至的核心还是使用了操作系统为用户特别开方的一个中断来实现。

2.6.2、异常

  • 当CPU再执行运行在用户态下的程序时,阿生了某些事先不可预知的异常,这时会触发有当前运行切换到处理此异常的内核相关程序中,也就转到了内核态。

2.6.3、外围设备的中断

  • 当外围设备完成用户其去年高俅的操作后,会向CPU发出相应的中断信号,,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果事先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的转换,

2.7、系统调用:

  • 是操作系统的最小功能单位,通过提供一些基本功能的接口供应用程序调用来调度内核空间管理的资源。当程序运行从用户态到内核态,那么处在用户态的进程需要先保存当前的数据以及运行的指令,方便回到用户态时继续执行,这中间还有很多其他的事情需要做,例如CPU寄存器需要保护和加载,系统调用器的二代吗需要执行等。

三、数据流

  • 计算机中的数据是基于随着时间变换高低电压信号传输的,这些数据信号连续不断,有着固定的传输方向,类似水管中水的流动,因此抽象数据流I/O流的概念:指义序有顺序的,有起点和终点的字节集合。
  • 抽象出数据流的作用:实现程序逻辑与底层硬件解耦,通过引入数据流作为程序与硬件设备之间的抽象层,面向通用的数据输出接口编程,而不是具体硬件特性,程序和底层硬件可以独立灵活替换和扩展。
  • System,IO.Stream类是所有流的抽象基类,Stream类及其派生类提供这些不同类型的输入和输出的一般视图,使程序员不必了解操作系统和基础设备的具体细节。
  • 根据基础数据源和储存库,流可能只支持这些功能中的一部分,用户可以通过使用CanRead、CanWrite和Canseek属性,可实现应用程序查询流的功能。
  • Read和Write方法读写各种不同格式的数据。对于支持查找的流,使用Seek和Setlength方法以及Position和Length属性可以查询和修改流的当前位置和长度。
  • 有些流用于实际执行基础数据的本地缓冲以提高性能,对于这样的流,Flush方法可以用于清除所有内部缓冲区并确保将所有的数据写入基础数据源或存储库。
  • 在Stream上调用Close将刷新所有缓冲区处理的数据,本质上使用用户调用Flush方法。Close也会释放操作系统资源,如文件句柄、网络连接或用于任何内部缓冲的内存,BufferedStream类提供了建一个讲过缓冲区的流环绕另一个流功能,一遍提高读写功能。
  • 如果需要不带后背存储区(即位存储桶)的流,应使用NULL。

四、IO工作原理

4.1、磁盘IO

典型的IO读写磁盘工作原理如下;

4.2、COU复制

  • 在DMA技术出现之前,应用程序与磁盘之间的I/O操作都是CPU的中断完成的,每次用户进程读取磁盘数据时,都需要CPU中断将数据读进暂存器,然后发起I/O请求等待 数据读取和拷贝完成,然后写进其他地方,每次的I/O中断都导致CPU的上下文切换。

4.3、DMA复制

  • DMA(Direct Memory Access,直接存储器访问),基于DMA访问方式,系统主内存与硬件设备的数据传输可以省去CPU的全程调度,
  • 具体流程:CPU对DMA控制器初始化,向I/O接口发出操作指令,I/O接口提出DMA请求DMA控制器对DMA请求判断优先级即评比,向总线裁决逻辑提出总线要求,当CPU执行完当前总线周期即可释放总线控制权,此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。
    • 值得注意的是:

      • 读写操作基于系统调用实现
      • 读写操作经过用户缓冲区,内核缓冲区,应用过程并不能直接操作磁盘
      • 应用进程读取操作时需阻塞直到读取到数据

4.4、网络I/O

  • 值得注意的是:

    • 网络I/O读写操作经过用户缓冲区,Socket缓冲区
    • 服务端线程在从调用开始到它返回有数据报准备好这段时间是阻塞的,read返回成功后,线程开始处理数据报

五、Java I/O流设计

5.1、流介绍

  • java中所有的数据都是使用流读写的,流是一组有顺序,有方向,有起点和重点的字节集合,是对数据传输的总称

5.2、流体系

5.3、流的实现类

5.4、java中流的划分

  • 按照方向划分

    • 输入流:从各种输入设备(磁盘、网卡、键盘……)将数据读取到当前程序中
    • 输出流:从当前程序将数据写入输出设备(磁盘、网卡、屏幕……)
  • 按照数据传输单元划分:
    • 字节流:一字节为单位的数据传输流,InputStream和OutputStream
    • 字符流:以字符为单位的数据传输流,Reader、Writer
  • 按照功能划分
    • 节点流:用于直接操作目标设备的流
    • 过滤流(高级流):对一个已经存在的流进行包装,以提供更强大灵活地读写功能。

5.5、java I/O原理

六、Java I/O系统

6.1、Java标准类库中各种各样的类以及它们的用法

6.1.1 File类

  • File(文件)这个类实际上既能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称;
  • 如果它指的是一个文件集,我们就可以对这个类调用list()方法,这个方法会返回一个字符数组,因为元素的个数是固定的,所以我们想取得不同的目录列表,只需要再创建一个不同的File对象就可以了
import java.io.File;import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;public class DirList {public static void main(String[] args) {File path=new File(".");String[] list;if (args.length==0){list=path.list();}else {list =path.list(new DirFilter(args[0]));Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);for (String dirItem:list){System.out.println(dirItem);}}}static class DirFilter implements FilenameFilter{private Pattern pattern;public DirFilter(String regex){pattern=Pattern.compile(regex);}@Overridepublic boolean accept(File dir, String name) {return pattern.matcher(name).matches();}}
}
  • 这里的DirFilter类实现了FilenameFilter接口,DIRFilter这个类存在的唯一原因就是将accept()方法,创建这个类的目的在与把accept()方法提供给list()使用,是的list()可以回调accept(),进而以决定那些文件包含在列表中。因此这种结构也常常成为回调。更具体的说,这是个策略模式的例子。因为list()实现了基本的功能,而且按照FilenameFilter的形式提供了这个策略,以便完善list()在提供服务时所需的算法。
  • accept()方法必须接受一个代表某个特定文件所在目录的File对象,以及包含了那个文件名的一个String。List()方法会为此目录对象下的每个文件名调用accept(),来判断该文件是否包含在内,判断借故偶有由accept返回的布尔值表示。
  • accept()会使用一个正则表达式的matcher对象,来查看此正则表达式regex是否匹配这个文件的名字,通过结果由accept(),list()方法会返回一个数组。

6.1.2 InputStream类型

  • InputStream的作用是用来表示那些从不同数据源产生输入的类,这些数据包括:

      1. 字节数组
      1. String对象
      1. 文件
      1. “管道”,工作方式与实际管道相似,即从一端输入,从另一端输出
      1. 一个有其他种类的流组成的序列,以便我们可以将它们收集合并到一个流内
      1. 其他数据源,如Internet连接等
        每一种数据源都有想用的InputStrean子类。另外,FilterInputStream也属于一种InputStream,为装饰器类(decorator)类提供基类,其中,装饰器类可以吧属性或有用的接口与是用户如流连接在一起,

6.1.3 OutputStream类型

  • 该类别的类决定了输出所要去往的目标,字节数组(但不是String)、文件或管道。
  • FilterOutStream为装饰器类提供了一个基类,装饰器类把属性或者有用的接口与输出流连接了起来。

6.2 I/O流的典型使用方式

6.2.1 缓冲输入文件

  • 如果想要打开一个文件用于字符输入,可以使用以String或File对象作为文件名的FileInputReader,为了提高速度,特别希望对那个文件进行缓冲,那么我们可以将所产生的引用传给一个BuferedReader构造器,由于BufferedReader也提供了readLine()方法,所以这是我们的最终对象和进行读取的接口,当readLIne()将返回null时,就达到了文件的末尾。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class BufferedInputFile {public static String  read(String filrname)throws IOException {BufferedReader in = new BufferedReader(new FileReader(filename));String s;StringBuffer sb = new StringBuffer();while (s = in.readLine() != null) {sb.append(s + "\n");in.close();return sb.toString();}}public static void main(String[] args)throws  IOException {System.out.print(read("BufferedInputFile.java"));}
}

字符串sb用来累积文件的全部内容,包括必须添加的换行符 ,因为readLine()已将它们删掉,最后,调用clode()关闭文件。

6.2.2基本的文件输出

  • FileWriter对象可以向文件中写入数据,首先,创建一个与指定文件连接的FileWriter,实际上,我们通常会用BufferedWriter将其包装起来用以缓冲输出(尝试移除此包装来感受对性能的影响——缓冲往往能此案朱的增加I/O操作的性能),在本例中,未来提供格式化机制,它被装饰城了PrintWriter,按照这种方式创建的数据问价可作为普通文本文件读取
import java.io.*;public class BasicFileOutput {static  String file="BasicFileOutput.out";public static void main(String[] args)throws IOException{BufferedReader in =new BufferedReader(new StringReader(BufferedReaderInputFile.read("BasicFileOutput.java")));PrintWriter out =new PrintWriter(new BufferedWriter(new FileWriter(file)));int lineCount=1;String s;while(s=in.readLine()!=null)out.println(lineCount++ +":"+ s);    out.close();System.out.println(BufferedInputFile.read(file));}
  • 当文本被写入文件时,行号就会增加,注意并未用到LineNumberInputStream,因为这个类没有多大帮助,所以我们没有必要用它,从这个例子可以看出,记录行号和容易。
  • 一旦读完输入流数据,readLine()就会返回null,我们可以看到要为out显示调用close(),如果我们不为所有的输出文件调用close(),就会发现缓冲区内容不糊被刷新清空,那么他们也就不完整。

6.2.3存储和恢复数据

  • PrintWriter可以对数据进行格式化,以便人们阅读,但是为了输出可供另一个流恢复的数据,我们需要用DataOutStream写入数据,并用DataInputStream恢复数据,当然,这些流可以是任意形式,但在下面的示例中使用的是一个文件,并且对于读和写都进行了缓冲处理,注意DataOutputStream和DataInputStream是面向字节的,因此要使用InputDtream和OutputStream.
import java.io.*;public class BasicFileOutput {public static void main(String[] args)throws IOException{DataOutputStream out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));out.writeDouble(3.14159);out.writeUTF("that is pi");out.writeDouble(1.41413);out.writeUTF("Square root of 2");DataOutputStream in =new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));System.out.println(in.readDouble());System.out.println(in.readUTF());System.out.println(in.readDouble());System.out.println(in.readUTF());}
}
  • 如果我们使用DataOutputStream写入数据,Java保证我们可以使用DataInputStream准确的读取数据——无论读和写数据的平台有多么不同,这一点很有价值,因为我们知道,人们曾经花费了大量的时间处理特定与平台的数据问题,只要两个平台上都有Java这个问题就不会再发生。
  • 当我们使用DataOutoutStream时,写字符串并且让DataInputStream能够恢复它的唯一可靠的做法就是使用UTF-8编码,在这个实例中是用writeUTF()和readUTF()来实现的。UTF-8是一种多字节的格式,其编码长度根据实际使用的字符集会有所变化,如果我们使用的只是ASCLL字符编码成单一字节的形式,而非ASCII字符则编码成两到三字节的形式,另外,字符串的长度存储在UTF-8字符串的前两个字节当中,但是writeUTF()和readUTF()使用的是适合于Java的UTF-8变体,因此如果我们用一个非java程序读取writeUTF()所写的字符串时,必须编写一些特殊代码才能正确读取字符串。
  • 有了writeUTF()和readUF(),我们可以用DataOutputStream把字符串和其他数据类型相混合,我们知道字符串完全可以作为Unicode来存储,并且可以很容易的使用DataInputStream来恢复它。
  • writeDouble()将Double类型的数字存储到流中,并用相应的readDouble()恢复它,(对于其他的数据类型,也有类似的方法用于读写)但是为了保证所有的读方法都能够正常工作,我们必须知道流中数据项所在的确切位置,因为极有可能将保存的double数据作为一个简单的字节序列。char或其他类型读入,因此,我们必须:要么为文件中的数据采用固定的行书,要么将额外的信息保存到文件中,以便能够对其进行解析以确定数据的存放位置,注意,对象序列化和XM可能是更容易的存储和读取复杂数据结构的方式。

6.2.4文件读写的使用工具

  • 一个很常见的程序化任务就是读取文件到内存,修改,然后再写出。Java I/O类库的问题之一就是:它需要编写相当多的代码去执行这些常用操作——没有人格基本的帮助功能可以为我们做这一切。更糟糕的是,装饰器会使得要记住如何打开文件变成一件相当困难的事,因此,在我们的类库中添加帮助类就显得相当有意义,这样就可以很容易的为我们完成这些基本任务,javaSE5在PrintWriter中添加了方便的构造器,因此你可以很方便的打开一个文本文件进行写入操作。但是,还有许多其他的常见的操作是你需要反复执行的,这就使得消除与这些任务相关联的重复代码就显得很有意义了。

6.2.5标准I/O

  • 标准I/O这个术语是Unix中“程序所使用的单一信息流”,程序的所有错误信息都可发送标准错误,标准I/O的意义在于我们可以很容易的吧把程序串联起来,一个程序的标准输出可以成为另一程序的标准输入,这是一个强大的工具。
  • 按照标准I/O模型,Java提供了System.in和System.err,通常我们会用readLine()一次次的读取输入,为此,我们将System.in包装成Buffered_Reader来使用,这要求我们必须用InputStreamReader把System.in转换成Reader,下面这个例子直接回显所输入的每一行。
public class Echo{Public static void main(String[] args)throws IOException{BufferedReader stdin=new BUfferedReader(new InputStreamReader(System.in));
String s;
while((s=stdin.readLine())!=null&&s.length()!=0)
System.out.println(s);}
}
  • 使用异常规范的是因为readLine()会抛出IOException,注意,System.In和大多数流一样,通常应该对他进行缓冲。
  • 标准I/O重定向
    • Java的System类提供了一些简单的静态方法调用,以允许我们对标准输入、输出和错误I/O流今次那个重定向:

      • setIn(InputStream)
      • setOut(PrintStream)
      • setErr(PrintStream)
  • 如果我们突然开始在显示器上创建大量输出,而这些输出滚动的太快以至于无法阅读时,重定向输出就显得极为有用,对于我们向重复测试某个特定用户的输入序列的命令行程来说,重定向输入就显得很有价值,下面简单演示了这些方法的使用:
Public class Redirecting{public static void main(String[] args)throws IOException{PrintStream console=System.out;
BufferedInputStream in=new BUfferedInputStream(new FileInputStream("Redirecting.java"));
PrintStream out=new PrintStream(newBufferedOutputStream( FileOutputStream("text.out")));
System.setIn(in);
System.setOut(out);
System.setErr(out);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String s;
while((s=br.readLine())!=null)
System.out.println(s);
out.close();
System.setOut(console);}
}
  • 这个程序将标准输入附接到文件上,并将标准输出和标准错误重定向到另一个问价中,注意,它在程序开头处存储了对最初的System.out的引用,并且在结尾处将系统输出恢复到了该对象上。
  • I/O重定向操纵的是字节流,而不是字符流,因此我们使用的是InputStream和OutputStream,,而不是Reader和Writer。

6.3进程控制

  • 我们经常需要在Java内部执行其他操作系统的程序,并且要控制这些程序的输入和输出,Java类库提供了执行这些操作的类
  • 一项常见的任务是运行程序,并将产生的输出发送的控制台,要想运行一个程序,你需要向OSExecute.command()传递一个command字符串,它与你在控制台上运行还程序所键入的命令相同,这个命令被传递给java.lang.ProcessBuilder构造器(他要求这个命令作为一个String对象序列而被传递),然后所产生的ProcessBuilder对象被启动:
public class OSException{public static void command(String commend){boolean err=false;
try{Process prcess=new ProcessBuilder(command.split(" ")).start();
String s;
while((s=results.readLine())!=nnull){System.out.println(s);
BufferedReader errors=new BufferesReader(new InputStreamReader(process.getErrorStream()));
while((s=errors.readLine())!=null){System.err.println(s);
err=true;}
}catch(Exception e){if(!command.startsWith("CMD /c"))
command("CMD /C"+ command);
else
throw new RuntimeException(e);
}
if(err)
throw new OSExecuteException("Errors executing"+ command);;}}
}
  • 为了捕获程序执行时产生的标准输出流,需要调用getInputStream(),这是因为InputStream是我们可以从中读取信息的流,从程序中产生的结果每次输出一行,因此要使用readLine()来读取。这里这些行知识直接被打印出来,但是你还可能希望从command()中捕获他们和返回错误,他们搜会被打印并且会抛出OSException()得以捕获,如果存在任何错误,它们都会被打印并且抛出OSException,因此调用程序需要处理这个问题。

6.4 新I/O

  • 速度的提高来自于所使用的的结构更接近于操作系统执行I/O的方式,通道和缓冲器,我们可以把它想象成一个煤矿,通道是一个包含煤层的矿藏,而缓冲器则是派送到矿藏的卡车,卡车载满煤炭而归,我们再从卡车上或的煤炭,也就是说,我们并没有直接和通道交互,我们只是和缓冲器交互,并把缓冲器派送的通道。通道要么从缓冲器获得数据,要么相缓冲器发送数据。
  • 唯一直接与通道交互的缓冲器是ByteBuffer,也就是说,可以存储未加工字节的缓冲器,当我们查询JDK文档中的java.nio.ByteBuffer时,会发现它是相当基础的类,通过高职分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用于以原始的字节星星或基本数据类型输出和读取数据,但是,没办法输出或读取对象,即使是字符串对象也不行,这种处理虽然很低级,但却正好,因为这是大多数操作系统中更有效的映射方式。
  • 就I/O类库中有三个类被修改了,用以产生FileChannel,这三个被修改的类是FileInputStream.FileOutputStream以及既读又写的RandomAccessFile.注意这些事字节操纵刘,与低层的nio性质一致,Reader和Writer这种字符模式类不能用于产生通道,但是java.nio.channels.Channels类提供了实用方法,用以在通道中产生Reader和Writer。
  • 下面的简单实例演示了上面三种类型的流,用以产生可写的,可读可写的及可读的通道。
public class GetChannels{private static final int BSIZE=1024;
public static void mian(String[] args)throws Exception{FileChannel fc=new FileOutputStream("data.txt").getChannel();
fc.write(ByteBuffer.wrap("Some text",getBytes()));
fc.close();
fc=new RandomAccessFile("data.txt","rw").getChannel();
fc.position(fc.size());
fc.write(ByteBuffer.wrap("Some more",getByte()));
fc.close();fc=new FileInputStream("Data.txt").getChannel();
ByteBuffer buff=ByteBuffer.allocate(BSIZE);
fc.read(buff);
buff.flip();
while(buff.hasRemaining())
System.out.print((char)buff.get());}
}
  • 对于这里所展示的任何流类,getChannel()将会产生一个FileChannel。通道是一种相当基础的东西,可以向他传送用于读写的ByteBuffer,并且可以锁定文件的某些区域用于独占式访问。
  • 将字节存放于ByteBuffer的方法之一是,使用一种“put”方法直接对他们进程填充,填入一个或多个字节,或基本数据类型的值,不过,正如所见,也可以使用warp()方法将已存在的字节数组包装到ByteBuffer中,一旦如此,就不在复制底层的数组,而是把它作为所产生的ByteBuffer的存储器,我们称之为数组支持的ByteBuffer.
  • data.txt文件用RandomAccessFile被再次打开,注意饿哦们可以在文件内随处移动FileChannel,在这里,我们把它移到最后,以便附加其他的写操作。
  • 对于只读访问,我们必须现式的使用静态的allocate()方法来分配ByteBuffer,nio的目标就是快速移动大量数据,因此ByteBuffer的大小就显得尤为重要——实际上,这里使用的1K可能比我们通常使用的小一点*(必须通过实际运行应用程序来找到最佳尺寸)。
  • 设置达到最高的速度也有可能,方法就是使用allocateDirect(),而不是allocate(),以产生一个与操作系统有更高耦合性的直接缓冲器,但是这种分配的开支会更大,并且具体实现也随操作系统的不同而不同,因此必须再次实际运行应用程序来查看直接缓冲是否可以使我们获得速度上的优势。
  • 一旦调用read()来高职FileChannel向ByteBuffer存储字节,就必须调用缓冲上的flip(),让它左傲让别人读取字节的准备,如果我们打算使用缓冲器执行进一步的read()操作,我们也必须得调用clean()来为每个read()做好准备。

6.5 压缩

  • Java I/O类库中的类支持读写压缩形式的数据流。可以用他们对其他的I/O类进行封装,以供压缩功能。
  • 这些类不是从Reader和Wrter类派生而来的,而是属于InputStream和OutStream继承层次结构的一部分,这样做是因为压缩类是按字节方式而不是字符方式处理的,不过有时我们可能会被迫要混合使用两种类型的数据流

I/O流(包括操作系统与内核,用户空间),I/O工作原理,Java I/O流的设计及Java IO系统相关推荐

  1. linux 内核态 cos函数,浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理

    浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理 文章来源:http://gliethttp.cublog.cn[转载请声明出处] //-------- ...

  2. 操作系统中的用户空间和内核空间

    在操作系统中,程序分为两类:用户程序和内核程序. 用户程序:Java.Python.C等编写的应用程序. 内核程序:文件读写.网络传输.进程和线程管理.调用系统资源等. 用户程序运行的空间就是用户空间 ...

  3. 嵌入式之linux用户空间与内核空间,进程上下文与中断上下文

    文章目录 前言 用户空间与内核空间 内核态与用户态 进程上下文和中断上下文 上下文 原子 进程上下文 中断上下文 进程上下文VS中断上下文 原子上下文 前言 之前在学习嵌入式linux系统的时候,一直 ...

  4. 用户user空间和内核kernel空间

    为了避免用户进程直接操作内核,保证内核安全,操作系统将虚拟内存划分为两部分,一部分是内核空间(Kernel-space)/ˈkɜːnl /,一部分是用户空间(User-space). 内核是操作系统的 ...

  5. LWN:DVB与头文件和用户空间的regression!

    关注了就能看到更多这么棒的文章哦- DVB, header files, and user-space regressions By Jake Edge August 25, 2021 DeepL a ...

  6. openflow协议的工作原理及流表的基本操作

    openflow协议的工作原理及流表的基本操作 1.openflow协议的工作原理 首先看一下python文件中的拓扑图,主机h1如果要与h3进行通信,h1向网络发送数据包,这里数据包发送给交换机s1 ...

  7. Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程

    操作系统 启动过程 通电 -> bios uefi 工作 -> 自检 -> 到硬盘固定位置加载bootloader -> 读取可配置信息 -> CMOS CMOS 用来存 ...

  8. 操作系统基础知识用户态和内核态的区别

    这节课给你带来了一道非常经典的面试题目:用户态线程和内核态线程有什么区别? 这是一个组合型的问题,由很多小问题组装而成,比如: 用户态和内核态是什么? 用户级线程和内核级线程是一个怎样的对应关系? 内 ...

  9. linux内核空间和用户空间的是怎样区别的,如何交互,如何从用户空间进入内核空间

    linux驱动程序一般工作在内核空间,但也可以工作在用户空间.下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们. Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,L ...

最新文章

  1. VBoxManage命令详解
  2. linux 保留最近目录,Linux如何删除全部目录只保留最新修改的目录
  3. 技术人解读企业为什么要平台化,关于数据中台你不知道的事...
  4. 带你了解几种二进制代码相似度比较技术
  5. 关于动态数组指针操作的两个例子
  6. JAVA CLASS混淆工具:JShrink简单试用
  7. 关于备考软考过程中历年真题的说明
  8. java-php-python-ssm制药企业人力资源管理系统计算机毕业设计
  9. 题目 1035: [编程入门]自定义函数之字符类型统计
  10. 嵌入式 linux 之 Lzma 移植
  11. “C++”读作「C 加加」,为什么“C♯”不能读作「C 井」呢?
  12. 2021年浏阴一中高考成绩查询,2021年湖南高考最高分多少分,历年湖南高考状元
  13. 慢啃《编程珠玑》【持续更新ing……】
  14. 如何巧妙的申请换部门_换部门申请书
  15. 18_NumPy数组ndarray中提取,删除满足条件的元素,行和列
  16. 一键备份微博并导出生成PDF,顺便用Python分析微博账号数据!
  17. duplicate symbol _*** in:
  18. C# CAD视图操作之缩放
  19. 短视频抖音矩阵玩法详细攻略大全丨国仁网络资讯
  20. 什么是POP3、SMTP及IMAP?POP3与IMAP的区别

热门文章

  1. 杭电选课脚本(一)登录选课系统
  2. 微信小程序实战 (WXSS:小程序版CSS、WXS:小程序版JavaScript)
  3. 一篇文章带你了解短信推送机制
  4. 一周新闻纵览:工信部组织召开综合整治骚扰电话专项行动;智能锁百万指纹泄密;4G不会降速5G网速会更快
  5. 中国国家气象局天气预报接口、爱帮网公交查询接口
  6. storm spout读取mysql_Storm中Spout使用注意事项小结
  7. 网络工程师笔记--计算机知识产权
  8. 三个堪称神器,却很少人使用的手机软件
  9. Flutter 保护你的APP数据安全
  10. 惊了!原来这就是今日头条的面试题!