2012-05-09 22 views
1

無限ループでファイルを作成して削除する(名前は変更されない)簡単なテストを作成しました。テストでは、秒(!時々、77,000以上の反復)のカップルのために実行し、その後、この例外で失敗しない:File.createNewFile()randomly fail

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"); 
     } 
    } 
} 

どのようにこれが可能である:

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) 

ここでテストロジックですか?削除呼び出しは失敗しません。それは伝えるだろう。したがって、常に削除は成功しますが、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; 
} 

は、誰もがこの動作を説明できますか?

+0

、私は明示的行動があったと述べhttp://stackoverflow.com/a/23697734/715269 – Gangnus

+0

@Gangnusランダム。そうです:いいえ、許可の問題ではありません。 –

+0

私は参照してください。私は似たような問題の解決策を探していたので、答えをここに入れています。あなたのページは私が読んだページの1つでした。私が解決策を見つけたら、将来誰かを助けるためのリンクを付けました。それはあなたの質問に対する答えまたは答えとして意味されておらず、回答としても公開されていません。 – Gangnus

答えて

2

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

私のアプリケーションだけでは、ファイルにアクセスするシステム上のプロセスではありません。たとえば、Windows Search Index Serviceは、このファイルをインデックスに追加したいので、このファイルを開くことができます。ビューを更新している場合は、Windowsエクスプローラ。私たちは、ファイルがでCreateNewFileを呼び出す前に、削除によって解放されることを保証する。このように

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"); 
      } 
     } 
    } 

+1

私はあなたのアンチウイルスソフトウェアであると確信しています。この種のことはいつもavで起こります。 –

+1

古いWindowsコンテンツインデックスサービスでは、この領域には厄介なバグがありました。ディレクトリをすばやく作成して削除した場合は、ディレクトリハンドル(おそらくFindFirstFileを使用)が開かれますが、それを閉じることができず、何もできないゾンビディレクトリが残ってしまいます。ゾンビを殺す唯一の方法は、インデックスサービスを再開することでした。 – arx

0

はこれを試してみてください。

+0

あなたのコードは失敗の可能性を低くしますが、成功を保証するものではありません。ファイルを10ms以上開いたままにするプロセスが残っている可能性があります。 –

+0

ファイルを削除する順序がOSに与えられたことに注意してください.OSコマンドの後にこのコマンドをブロックする必要はありません。 –

+0

確実にするには、f.createNewFile()でjava.io.IOExceptionを捕捉してから、再試行してから10ミリ秒待ってください。 –

0

この問題は、File.renameTo()メソッドで最近経験した問題を思い出させます。 (...それが動作します)

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

奇妙な回避策はにSystem.gcを呼び出すために()して、再度ファイルの名前を変更再試行することです:それはあるJVMにこのバグに(?)でした。

わからない...それはあなたの問題とのリンクを持っているが、それは探検する価値があるかもしれ