当应用程序请求打开或操作文件时,操作系统会为该应用程序提供一个文件列表,并分配一个非负整数作为索引号。这个索引号就像地址或指针,用于在内存中定位文件数据。在类unix系统中,这个索引号被称为文件描述符,而在windows系统中则被称为句柄,用于标识各种对象。
文件描述符是类Unix系统中用于描述任何资源对象的概念,类似于Java中的class对象。在Java中,文件描述符的概念通过java.io.FileDescriptor类来抽象。对于FileInputStream、FileOutputStream和RandomAccessFile,使用handle来表示底层的文件句柄;而对于ServerSocket和Socket,则使用fd来表示底层的文件句柄。文件描述符的无效值为-1。
文件描述符类的实例用作与基础机器相关的某种结构的不透明句柄,用于表示打开的文件、套接字或其他字节源或接收者。主要用于创建包含该结构的FileInputStream或FileOutputStream。应用程序不应自行创建文件描述符,因为它们是由操作系统提供的。
文件描述符就像电话号码,通过它可以定位到具体的文件或资源,但它本身并不是文件或资源。应用程序在需要服务时,将文件描述符传递给操作系统,由操作系统处理具体操作。文件描述符是操作系统管理和维护的抽象概念,应用程序通过请求操作系统来进行文件操作。
在Java中,FileDescriptor类内置了三个文件描述符,分别是标准输入(in)、标准输出(out)和标准错误(err)。它们的具体值分别是0、1和2,这些值是操作系统层面的描述。在linux中,每个进程启动时会打开这三个文件。
文件描述符通常不直接使用,而是通过System.in、System.out和System.err来访问。这些标准输入输出是共享的,但在Java的多线程环境中需要特别处理。在系统初始化之前,线程不能使用这些对象。System类在加载时会将它们初始化为NULL,之后通过initializeSystemClass方法进行初始化。
initializeSystemClass方法使用这三个文件描述符创建FileInputStream和FileOutputStream对象。对于out和err,根据编码转换为PrintStream,然后通过本地方法进行设置。因此,应用程序不直接创建文件描述符,而是通过系统调用和本地方法来操作和使用它们。