File.createNewFile()随机失败

时间:2012-05-09 12:48:21

标签: java winapi createfile

我构建了一个简单的测试,它在无限循环中创建和删除文件(名称不会更改)。测试确实运行了几秒钟(有时超过77,000次迭代!)然后因此异常而失败:

Exception in thread "main" java.io.IOException: Access is denied
        at java.io.WinNTFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(Unknown Source)
        at DeleteTest.main(DeleteTest.java:11)

这是测试逻辑:

final File f = new File(pathname);
while (true) {
    final boolean create = f.createNewFile();
    if (!create) {
        System.out.println("crate failed");
    } else {
        final boolean delete = f.delete();
        if (!delete) {
            System.out.println("delete failed");
        }
    }
}

这怎么可能?删除调用不会失败。它会说。因此删除总是成功,但createNewFile失败。这是MSDN关于win32 api函数DeleteFile的说法:

  

DeleteFile函数在关闭时标记要删除的文件。因此,   直到文件的最后一个句柄是,才会发生文件删除   关闭。随后调用CreateFile以打开文件失败   ERROR_ACCESS_DENIED。

所以createNewFile没有关闭文件? openjdk源告诉我们文件 已关闭:

JNIEXPORT jboolean JNICALL
Java_java_io_Win32FileSystem_createFileExclusively(JNIEnv *env, jclass cls,
                                                   jstring pathname)
{
    jboolean rv = JNI_FALSE;
    DWORD a;

    WITH_PLATFORM_STRING(env, pathname, path) {
        int orv;
        int error;
        JVM_NativePath((char *)path);
        orv = JVM_Open(path, JVM_O_RDWR | JVM_O_CREAT | JVM_O_EXCL, 0666);
        if (orv < 0) {
            if (orv != JVM_EEXIST) {
                error = GetLastError();

                // If a directory by the named path already exists,
                // return false (behavior of solaris and linux) instead of
                // throwing an exception
                a = GetFileAttributes(path);

                if ((a == INVALID_FILE_ATTRIBUTES) ||
                        !(a & FILE_ATTRIBUTE_DIRECTORY)) {
                    SetLastError(error);
                    JNU_ThrowIOExceptionWithLastError(env, path);
                }
            }
        } else {
            JVM_Close(orv);
            rv = JNI_TRUE;
        }
    } END_PLATFORM_STRING(env, path);
    return rv;
}

任何人都可以解释这种行为吗?

3 个答案:

答案 0 :(得分:2)

我在写这个问题时找到了解释。我仍然发布了这个问题,因为我想分享我学到的东西。

我的应用程序不是系统访问文件的唯一过程。例如,Windows搜索索引服务可以打开此文件,因为它希望将其添加到其索引中。或Windows资源管理器,如果它正在更新视图。

答案 1 :(得分:0)

试试这个:

final File f = new File("file");
    while (true) {
        final boolean create = f.createNewFile();
        if (!create) {
            System.out.println("crate failed");
        } else {
            final boolean delete = f.delete();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                System.out.println("...");
            }
            if (!delete) {
                System.out.println("delete failed");
            }
        }
    }

通过这种方式,我们确保在调用createNewFile之前删除文件。

答案 2 :(得分:0)

此问题提醒我最近使用File.renameTo()方法遇到的问题。由于jvm中的这个错误,它是(是?):

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213298

一个奇怪的解决方法是调用System.gc()并重新重命名该文件(它可以工作......)。

不确定它是否与您的问题有关联,但可能值得探索......