📓 Archive

  • Pricing
  • Chess
  • Syntax
  • IO

    FGJ: Create:2024/01/13 Update: (2024-10-24)

    • Structure #

    • FileDescriptor #

      文件描述符类的实例充当底层机器特定结构的不透明句柄,表示打开的文件、打开的套接字或另一个字节源或接收器。文件描述符的主要实际用途是创建FileInputStream或FileOutputStream来包含它。

      它相当于将指定文件的信息与新建的文件指针fp相关联,在 FILE 结构内部记录了这样一些信息:文件内部的当前读写位置、读写报错的记录、文件结尾指示器、缓冲区开始位置的指针、文件标识符、一个计数器(统计拷贝进缓冲区的字节数)等等。后继的操作就可以使用这个指针(而不是文件名)来处理指定文件。 参考

    • InputStream #

      signature: public abstract class InputStream implements Closeable {}

      • FileInputStream #

        • 摘抄代码 #

          jdk代码来自【openjdk 23-internal】

          package java.io;
          
          import java.nio.channels.FileChannel;
          import sun.nio.ch.FileChannelImpl;
          
          public
          class FileInputStream extends InputStream
          {
              /* File Descriptor - handle to the open file */
              private final FileDescriptor fd;
          
              /**
              * The path of the referenced file
              * (null if the stream is created with a file descriptor)
              */
              private final String path;
          
              public FileInputStream(String name) throws FileNotFoundException {
                  this(name != null ? new File(name) : null);
              }
          
              public FileInputStream(File file) throws FileNotFoundException {
                  String name = (file != null ? file.getPath() : null);
                  SecurityManager security = System.getSecurityManager();
                  if (security != null) {
                      security.checkRead(name);
                  }
                  if (name == null) {
                      throw new NullPointerException();
                  }
                  if (file.isInvalid()) {
                      throw new FileNotFoundException("Invalid file path");
                  }
                  fd = new FileDescriptor();
                  fd.attach(this);
                  path = name;
                  open(name);
              }
          
              private native void open0(String name) throws FileNotFoundException;
          
              private void open(String name) throws FileNotFoundException {
                  open0(name);
              }
          
              private static native void initIDs();
          
              private native void close0() throws IOException;
          
              static {
                  initIDs();
              }
          }
          
          jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
          
          /**************************************************************
          * static methods to store field ID's in initializers
          */
          
          JNIEXPORT void JNICALL
          Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) {
              fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
          }
          
          /**************************************************************
          * Input stream
          */
          
          JNIEXPORT void JNICALL
          Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
              fileOpen(env, this, path, fis_fd, O_RDONLY);
          }
          
          JNIEXPORT jint JNICALL
          Java_java_io_FileInputStream_read0(JNIEnv *env, jobject this) {
              return readSingle(env, this, fis_fd);
          }
          
          void
          fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
          {
              WITH_PLATFORM_STRING(env, path, ps) {
                  FD fd;
          
          #if defined(__linux__) || defined(_ALLBSD_SOURCE)
                  /* Remove trailing slashes, since the kernel won't */
                  char *p = (char *)ps + strlen(ps) - 1;
                  while ((p > ps) && (*p == '/'))
                      *p-- = '\0';
          #endif
                  fd = handleOpen(ps, flags, 0666);
                  if (fd != -1) {
                      jobject fdobj;
                      jboolean append;
                      fdobj = (*env)->GetObjectField(env, this, fid);
                      if (fdobj != NULL) {
                          // Set FD
                          (*env)->SetIntField(env, fdobj, IO_fd_fdID, fd);
                          append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
                          (*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
                      }
                  } else {
                      throwFileNotFoundException(env, path);
                  }
              } END_PLATFORM_STRING(env, ps);
          }
          
          /* field id for jint 'fd' in java.io.FileDescriptor */
          jfieldID IO_fd_fdID;
          
        • 构造器初始化解读 #

          1. 调用静态方法initIDs()用来初始化FileDescriptor fd属性,此处并不是赋值,而是让FileInputStream.c 中的fis_fd保存属性位置。方便后续通过C代码能够获取当前fd属性对象。近而对当前FileInputStream中的fd对象中的属性fd赋值真正的文件描述符id,例如整型值23.
          2. 通过open0()方法调用原生方法获取1中需要的文件描述符id,
            2.1 将fis_fd通过fileOpen函数传入io_util_md.c中.
            2.2 fd = handleOpen(ps, flags, 0666);尝试打开给定路径的文件。获取文件描述符id。
          3. 将2中获取的文件描述符id赋值给FileInputStream中的fd对象中的属性fd
            3.1 fdobj = (*env)->GetObjectField(env, this, fid); 获取当前FileInputStream对象中的FileDescriptor fd这个对象。
            3.2 (*env)->SetIntField(env, fdobj, IO_fd_fdID, fd); IO_fd_fdID 定义在FileDescriptor_md.c文件中。对3.1中的对象fdobj赋值 fd.
          4. 后续原生读写都会通过这个FD进行。

    Reference #


    comments powered by Disqus