Вопрос

I am dealing with a java.nio.file.AccessDeniedException problem.

I have a Scala program where if I do:

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

Everything works fine. I have some code where I do

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))

But when I try to delete the same file, I get

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

The best I can tell is that the JVM is either holding a lock on the file or the directory the file is in, but I cannot figure out where. The code that checks to see if files are identical looks like

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()
  }
}

I would have thought that closing the channels would free any file locks the JVM needs. This is the only part of the code where I actually open the files for reading, although other parts of the code do check the file lengths, but I would not expect the JVM to need a file lock for that.

What other reasons would the JVM be holding file locks? How can I find out, and how can I free them?

Cheers, Eric

Это было полезно?

Решение

I only know what the JavaDoc says:

A mapping, once established, is not dependent upon the file channel that was used to create it. Closing the channel, in particular, has no effect upon the validity of the mapping.

and

A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.

You may not be holding onto the buffer, but maybe it's not been GC'd either.

Update: I'll reboot into windows later to try it out, but this wouldn't be a problem on linux.

Update: ...but on windows, yes, that is the problem.

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

Trying it out:

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

Or:

Release Java file lock in Windows

How to unmap a file from memory mapped using FileChannel in java?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top