设为首页 加入收藏

TOP

JDK 源码阅读 : FileDescriptor(三)
2018-06-07 09:21:34 】 浏览:832
Tags:JDK 源码 阅读 FileDescriptor
(参考使用 Java Native Interface 的最佳实践

标准输入,标准输出,标准错误输出

标准输入,标准输出,标准错误输出是所有操作系统都支持的,对于一个进程来说,文件描述符0,1,2固定是标准输入,标准输出,标准错误输出。

Java对标准输入,标准输出,标准错误输出的支持也是通过FileDescriptor实现的,FileDescriptor中定义了in,out,err这三个静态变量:

public static final FileDescriptor in = new FileDescriptor(0);
public static final FileDescriptor out = new FileDescriptor(1);
public static final FileDescriptor err = new FileDescriptor(2);

 

我们常用的System.out等,就是基于这三个封装的:

public final class System {
    public final static InputStream in = null;
    public final static PrintStream out = null;
    public final static PrintStream err = null;
    /**
    * Initialize the system class.  Called after thread initialization.
    */
    private static void initializeSystemClass() {
        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
        setIn0(new BufferedInputStream(fdIn));
        setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
        setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
    }
    private static native void setIn0(InputStream in);
    private static native void setOut0(PrintStream out);
    private static native void setErr0(PrintStream err);
}

System作为一个特殊的类,类构造时无法实例化in/out/err,构造发生在initializeSystemClass被调用时,但是in/out/err是被声明为final的,如果声明时和类构造时没有赋值,是会报错的,所以System在实现时,先设置为null,然后通过native方法来在运行时修改(学到了不少奇技淫巧。。),通过setIn0/setOut0/setErr0的注释也可以说明这一点:

/*
 * The following three functions implement setter methods for
 * java.lang.System.{in, out, err}. They are natively implemented
 * because they violate the semantics of the language (i.e. set final
 * variable).
 */
JNIEXPORT void JNICALL
Java_java_lang_System_setIn0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}
JNIEXPORT void JNICALL
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}
JNIEXPORT void JNICALL
Java_java_lang_System_setErr0(JNIEnv *env, jclass cla, jobject stream)
{
    jfieldID fid =
        (*env)->GetStaticFieldID(env,cla,"err","Ljava/io/PrintStream;");
    if (fid == 0)
        return;
    (*env)->SetStaticObjectField(env,cla,fid,stream);
}

FileDescriptor关闭逻辑

FileDescriptor的代码不多,除了上面提到的fd成员变量,initIDs初始化构造方法,in/out/err三个标准描述符,只剩下attachcloseAll这两个方法,这两个方法和文件描述符的关闭有关。

上文提到过,FileInputStream在实例化时,会新建FileDescriptor并调用FileDescriptor#attach方法绑定文件流与文件描述符。

public FileInputStream(File file) throws FileNotFoundException {
    String name = (file != null ? file.getPath() : null);
    fd = new FileDescriptor();
    fd.attach(this);
    path = name;
    open(name);
}

FileDescriptor#attach实现如下:

synchronized void attach(Closeable c) {
    if (parent == null) {
        // first caller gets to do this
        parent = c;
    } else if (otherParents == null) {
        otherParents = new ArrayList<>();
        otherP
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Spring Boot 自动配置的 “魔法”.. 下一篇RocketMQ 源码学习 4 : 消息发送

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目