我构建了一个简单的测试,它在无限循环中创建和删除文件(名称不会更改)。测试确实运行了几秒钟(有时超过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关于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 :(得分:2)
我在写这个问题时找到了解释。我仍然发布了这个问题,因为我想分享我学到的东西。
我的应用程序不是系统访问文件的唯一过程。例如,Windows搜索索引服务可以打开此文件,因为它希望将其添加到其索引中。或Windows资源管理器,如果它正在更新视图。
答案 1 :(得分: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之前删除文件。
答案 2 :(得分:0)
此问题提醒我最近使用File.renameTo()方法遇到的问题。由于jvm中的这个错误,它是(是?):
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213298
一个奇怪的解决方法是调用System.gc()并重新重命名该文件(它可以工作......)。
不确定它是否与您的问题有关联,但可能值得探索......