首页 > 代码库 > 不要在linux上使用java 7 Files的接口参数StandardOpenOption.DELETE_ON_CLOSE

不要在linux上使用java 7 Files的接口参数StandardOpenOption.DELETE_ON_CLOSE

最近在看安全代码规范建议中提到关于如何删除创建的临时文件,推荐使用jdk7中的Files的函数,通过参数StandardOpenOption.DELETE_ON_CLOSE来控制

代码示例

BufferedWriter writer = Files.newBufferedWriter(tempFile, Charset.forName("UTF8"), StandardOpenOption.DELETE_ON_CLOSE)

只要当文件close掉,这个文件就会自动被系统删除,这样可以避免在一些场景下忘了删除产生的临时文件。

StandardOpenOption.DELETE_ON_CLOSE参数

我们来看代码StandardOpenOption.DELETE_ON_CLOSE参数在linux下究竟控制了什么,我们在java代码中看到了参数的控制阀

if (flags.deleteOnClose) {
            try {
                if (dfd >= 0) {
                    unlinkat(dfd, path.asByteArray(), 0);
                } else {
                    unlink(path);
                }
            } catch (UnixException ignore) {
                // best-effort
            }
        }

java的unlink函数

static void unlink(UnixPath path) throws UnixException {
        NativeBuffer buffer = copyToNativeBuffer(path);
        try {
            unlink0(buffer.address());
        } finally {
            buffer.release();
        }
    }


JNI unlink0函数

JNIEXPORT void JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,
    jlong pathAddress)
{
    const char* path = (const char*)jlong_to_ptr(pathAddress);

    /* EINTR not listed as a possible error */
    if (unlink(path) == -1) {
        throwUnixException(env, errno);
    }
}
最后调用了系统unlink函数

unlink rm unlinkat remove的区别

 我们通常会使用shell rm去删除文件,让我们先看看rm做了什么,通过strace来查看系统调用strace rm filepath会看到最后调用的函数unlinkat

unlink 和 unlinkat 的区别

unlinkat 可以通过参数AT_REMOVEDIR删除空的目录,其他的是和unlink一样

unlinkat(AT_FDCWD, "/tmp/test", AT_REMOVEDIR) 

remove 和 unlink的区别

remove是unlink 和 rmdir 合集,区别也是在删除目录上

可以看到说参数StandardOpenOption.DELETE_ON_CLOSE 在linux上是调用了unlink删除了文件名,那么也就意味着你对这个文件的任何读写操作都是无效的。

Linux和windows的区别

参数StandardOpenOption.DELETE_ON_CLOSE在Linux和windows是不一样的实现,windows上只有调用了writer.close() 这个文件才会被删除,也就是windows上的open函数本身就带有文件属性FILE_FLAG_DELETE_ON_CLOSE,当显式的调用close,自然就会删除该文件,而如果进程退出也会删除这个文件。


 总结:

参数StandardOpenOption.DELETE_ON_CLOSE对Linux 来说是无效的操作,虽然保证了文件的删除,但也违反了本身API的协议(需要调用close才能真实的删除文件)。

而且本身也没有实际意义,因为文件已经被删除了,那就意味着本身也无法向文件中写任何内容,那么创建临时文件的意义也不存在了。这个函数在windows上是实现的,而Linux中没有类似的内核函数去实现这样的功能。

File函数的方法deleteOnExit

File.deleteOnExit()


这个方法在jvm退出时添加了一个钩子,退出时删除文件。但是如果jvm没有正常退出呢?比如我们常用的信号退出,就没有办法正常删除文件。

StandardOpenOption.DELETE_ON_CLOSE这是需要在内核函数中去实现这个属性,而不是在jvm 应用层去实现,而jvm 在针对Linux 直接调用unlink 也是避免了问题的复杂化。

 

 

不要在linux上使用java 7 Files的接口参数StandardOpenOption.DELETE_ON_CLOSE