1

java.nio.file.AccessDeniedException の問題に対処しています。

私は Scala プログラムを持っています。

java.nio.file.Files.delete(FileSystems.getDefault().getPath("""D:\Users\Eric\Google Drive (New)\Music\Downloaded\Foreigner [Discography HQ]\1977 - Foreigner\03 - Starrider.mp3""")) 

すべて正常に動作します。私が行うコードがいくつかあります

def delete(path : Path) {
  try {
    println("deleting " + path)
    java.nio.file.Files.delete(path)
  } catch {
    case exception: Exception => System.err.println(exception)
  }
}

val google1 = FileSystems.getDefault().getPath("""D:\Users\Eric\Google Drive\Music\Downloaded\Foreigner [Discography HQ]""")
val google2 = FileSystems.getDefault().getPath("""D:\Users\Eric\Google Drive (New)\Music\Downloaded\Foreigner [Discography HQ]""")

val duplicates = TraversablePaths(List(google1, google2)).duplicateFilesList

println("deleting duplicate files")
duplicates.foreach(_.filter(!_.startsWith(google1)).foreach(delete))

しかし、同じファイルを削除しようとすると、

java.nio.file.AccessDeniedException: D:\Users\Eric\Google Drive (New)\Music\Downloaded\Foreigner [Discography HQ]\1977 - Foreigner\03 - Starrider.mp3

私が言える最善のことは、JVM がファイルまたはファイルが存在するディレクトリをロックしているということですが、どこにあるのかわかりません。ファイルが同一かどうかを確認するコードは次のようになります

def identical(file1 : Path, file2 : Path) : Boolean = {

  require(isRegularFile(file1), file1 + " is not a file")
  require(isRegularFile(file2), file2 + " is not a file")

  val size1 = size(file1)
  val size2 = size(file2)

  if (size1 != size2) return false

  var position : Long = 0
  var length = min(Integer.MAX_VALUE, size1 - position)

  val channel1 = FileChannel.open(file1)
  val channel2 = FileChannel.open(file2)

  try {
    while (length > 0) {
      val buffer1 = channel1.map(MapMode.READ_ONLY, position, length)
      val buffer2 = channel2.map(MapMode.READ_ONLY, position, length)
      if (!buffer1.equals(buffer2)) return false
        position += length
    length = min(Integer.MAX_VALUE, size1 - position)
    }
    true
    } finally {
    channel1.close()
    channel2.close()
  }
}

チャネルを閉じると、JVM が必要とするファイル ロックが解放されると思っていたでしょう。これは、実際にファイルを読み取り用に開くコードの唯一の部分です。コードの他の部分はファイルの長さをチェックしますが、JVM がそのためにファイル ロックを必要とすることはないと思います。

JVM がファイル ロックを保持している他の理由は何ですか? どうすれば見つけられますか? また、どうすればそれらを解放できますか?

乾杯、エリック

4

1 に答える 1

5

私はJavaDocが何を言っているのかしか知りません:

いったん確立されたマッピングは、それを作成するために使用されたファイル チャネルに依存しません。特に、チャネルを閉じても、マッピングの有効性には影響しません。

マップされたバイト バッファーとそれが表すファイル マッピングは、バッファー自体がガベージ コレクションされるまで有効なままです。

バッファーを保持していない可能性がありますが、GC も行われていない可能性があります。

更新: 後で Windows を再起動して試してみますが、これは Linux では問題になりません。

更新: ...しかし、Windows では、はい、それが問題です。

package niolock

import java.nio.channels._
import java.nio.file._
import FileChannel.MapMode.{ READ_ONLY => RO }

import scala.util._

object Test extends App {
  val p = FileSystems.getDefault getPath "D:/tmp/mapped"
  val c = FileChannel open p
  var b = c map (RO, 0L, 100L)
  c.close

  Console println Try(Files delete p)
  b = null
  System.gc()
  Console println Try(Files delete p)
}

試してみます:

$ scalac niolock.scala ; scala niolock.Test
Failure(java.nio.file.AccessDeniedException: D:\tmp\mapped)
Success(())

または:

Windows で Java ファイル ロックを解除する

JavaでFileChannelを使用してマップされたメモリからファイルをマップ解除する方法は?

于 2014-03-12T02:51:47.237 に答える