1

無限ループでファイル(名前は変更されません)を作成および削除する簡単なテストを作成しました。テストは数秒間実行され(場合によっては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がwin32api関数について言っていることです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;
}

誰かがこの行動を説明できますか?

4

3 に答える 3

2

質問を書いているときに説明を見つけました。学んだことを共有したかったので、まだ質問を投稿しました。

私のアプリケーションは、ファイルにアクセスするシステム上の唯一のプロセスではありません。たとえば、Windows Search Index Serviceは、このファイルをインデックスに追加したいので、このファイルを開くことができます。または、ビューを更新している場合はWindowsエクスプローラー。

于 2012-05-09T12:53:50.613 に答える
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を呼び出す前に、ファイルが削除によって解放されることを確認します。

于 2012-05-09T13:07:24.697 に答える
0

この問題は、最近File.renameTo()メソッドで発生した問題を思い出させます。これは、jvmのこのバグが原因です:

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

奇妙な回避策は、System.gc()を呼び出して、ファイルの名前の変更を再試行することです(そしてそれは機能します...)。

問題との関連性があるかどうかはわかりませんが、調査する価値があるかもしれません...

于 2012-05-09T13:41:58.460 に答える