Reputation: 2243
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
Upvotes: 1
Views: 3490
Reputation: 39577
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?
Upvotes: 5