[一]FileDescriptor文件描述符 标准输入输出错误 文件描述符

文件描述符

当应用程序请求打开或者操作文件时,操作系统为应用程序设置一张文件列表,具体的实现形式此处不深入说明

操作系统会提供给你一个非负整数,作为一个索引号,它的作用就像地址或者说指针或者说偏移量

这个索引号就用来定位文件数据在内存中的位置.

这个概念在类Unix系统叫做文件描述符, linux把所有东西都被看成是文件,比如文件、目录、进程、网络socket、各种硬件设备等

这个概念在Windows下 称之为句柄, 句柄是Windows下各种对象的标识符, 比如文件、资源、菜单、光标、位图等

那么,现在你应该可以理解文件描述符的含义了

文件描述符  之于文件系统(操作系统中的一切都是文件描述符 可以使用文件描述符描述任何一个资源对象 就如同Class 之于java语言一样(java中一切都是类,都是一个Class的实例,任何一个类都用Class对象的实例来描述

Java中使用FileDescriptor 来抽象文件描述符这一概念

package java.io;

对于FileInputStream/FileOutputStream/RandomAccessFile,使用handle来表示底层的文件句柄

对于ServerSocket/Socket,使用fd来表示底层的文件句柄

FileDescriptor的fd和handle的无效值是-1

看下API的描述:

文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄 该结构表示开放文件、开放套接字或者字节的另一个源或接收者。 文件描述符的主要实际用途是创建一个包含该结构的 FileInputStream 或 FileOutputStream。   应用程序不应创建自己的文件描述符。

其实说白了,就是文件描述符的实例,就是用来表示文件的一个指针/索引. 操作系统通过这个值与应用程序交互

如同你的电话号码一样,在很多场景,他就相当于你,   虽然,他完全不是你,

比如朋友想找你聊天,有人托你办事,保险公司推销等等,通过电话都可以定位到你

而且,你自己能造一个电话号码么?显然不行,必须是运营商提供给你的

我们的文件描述符,也是如此,应用程序不应该创建自己的文件描述符

他的构造方法,只能创建一个无效的文件描述符

不应该创建自己的文件描述符,可以直接理解为:

这东西是底层实现的内容,操作系统来传递给你

而且,对于文件的其他的一些操作,最底层的实现也仍旧是操作系统来搞

这就相当于操作系统给你的一个指针,钥匙

你需要服务的时候,拿给操作系统即可,具体到底怎么玩,你管不上,也管不了

想要理解文件描述符只需要理解,文件的抽象概念是操作系统负责管理维护的

应用程序都是在请求操作系统帮忙,JVM也就是个应用程序

不管那个位置到底存放的是什么,对于应用程序来说就是一个描述符

操作系统提供了一致性的接口访问途径,就是通过这个描述符

描述符背后到底是什么,操作系统屏蔽了这些东西

这样子的实现,对应用程序程序员来说,就是不需要在关注他到底是个什东西,操作系统来搞定

FileDescriptor中的三个描述符

FileDescriptor 内置了三个文件描述符 分别是  in   out  err

类型是FileDescriptor  这是java层面的描述

具体的值是 0  1   2  ,这是操作系统层面的描述

在linux 中, 每个进程启动时都打开3个文件(linux 中一切都是文件): 

* 标准输入  0

* 标准输出  1

* 标准错误  2

三个描述符,通过调用私有方法 standardStream进行创建初始化 创建一个FileDescriptor 并且,设置他的handle值 内部的set(fd)是一个本地方法 说白了,就是通过调用本地方法,获得操作系统对标准输入/输出/错误的三个文件描述符

注释中也说的很清楚,文件描述符一般不直接使用通过使用System.in  System.out System.err

文件描述符在System类中的应用

在System 中   in  out err  都是 final  static的

标准的输入输出是共享,但是java是多线程的 因此它们必须受到特别的处理,在系统初始化完成之前,线程严禁使用这几个特殊对象; 又因为这些对象都是静态的,因此java的类加载机制会在System类加载的时候就会初始化,这就造成了一对矛盾; 为解决这对矛盾,System在加载是将它们初始化为null,等加在完成后,通过  initializeSystemClass

System中in out  err中的定义部分,全都是final static

注释中也很明确的说明了 将会调用 initializeSystemClass  进行部分初始化工作

initializeSystemClass 方法的关键部位 以及 本地的setIn0 setOut0 setErr0

initializeSystemClass 方法对于这块来说,主要就是 使用三个文件描述符  创建了 FileInputStream  以及 FileOutputStream 对于Out以及Err又根据encoding 转换为PrintStream 然后通过本地方法进行设置

所以说,那三个专门的文件描述符一般不直接使用取而代之的则是使用文件描述符 初始化设置过的流对象

应用程序不创建文件描述符, 都是由系统调用, 也就是本地方法来操作的 应用程序只是获得,  然后使用,  所谓使用,最终也还是需要借助于操作系统 是应用程序 操作文件 时 与操作系统进行交互时,必须的数据项

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏magicsoar

C++ socket网络爬虫(1)

C++写的socket网络爬虫,代码会在最后一次讲解中提供给大家,同时我也会在写的同时不断的对代码进行完善与修改 我首先向大家讲解如何将网页中的内容,文本,图片...

59150
来自专栏猿人谷

内存泄露

1.简介       在计算机科学中,内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理...

24180
来自专栏开源优测

RobotFramework怎么写好用例

github地址:https://github.com/robotframework/HowToWriteGoodTestCases/blob/master/H...

11120
来自专栏前端知识分享

第217天:深入理解Angular双向数据绑定的原理

双向绑定是新的前端框架中频繁出现的一个新词汇,也是mvvm的核心原理。angularjs五条核心信念中的数据驱动,便是由双向绑定进行完成。

19620
来自专栏java 成神之路

vmstat 命令详解

47770
来自专栏技术栈大杂烩

H5: 表单验证失败的提示语

    前端的童鞋在写页面时, 都不可避免的总会踩到表单验证这个坑. 这时候, 我们就要跪了, 因为要写一堆js来检查. 但是自从H5出现后, 很多常见的表达验...

28820
来自专栏屈定‘s Blog

工作--如何封装第三方服务?

业务开发中经常会对接某某第三方服务,因此会经常写一些SDK供服务使用,一种比较好的做法就是使用命令模式封装第三方服务,命令模式对于调用方来说简洁明了,也正是封装...

24720
来自专栏Python攻城狮

Redis的安装及基本使用1.Redis2.Redis安装3.redis常见配置4.redis数据操作5.redis发布订阅6.主从双备

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如 字符串(strings), ...

7810
来自专栏社区的朋友们

在共享内存实现 Redis(下)

从实现方式入手,设计了一种综合二者优点的方案:将 Redis 做成数据逻辑分离,数据存放共享内存,进程只负责存储逻辑,同时解决 Redis 长命令卡顿和 for...

45000
来自专栏开源优测

RobotFramework怎么写好用例

github地址:https://github.com/robotframework/HowToWriteGoodTestCases/blob/master/H...

29820

扫码关注云+社区

领取腾讯云代金券