java.io 上的 FileNotFound(访问被拒绝)异常

Posted

技术标签:

【中文标题】java.io 上的 FileNotFound(访问被拒绝)异常【英文标题】:FileNotFound (Access is denied) Exception on java.io 【发布时间】:2011-12-25 22:34:27 【问题描述】:

为什么我在运行这个程序时会收到这个错误?这发生在随机迭代之后。通常在第 8000 次迭代之后。

public static void main(String[] args)

    FileWriter writer = null;
    try
    
        for(int i = 0; i < 10000; i++)
        
            File file = new File("C:\\Users\\varun.achar\\Desktop\\TODO.txt");

            if(file.exists())
            
                System.out.println("File exists");
            
            writer = new FileWriter(file, true);
            writer.write(i);
            System.out.println(i);
            writer.close();
            if(!file.delete())
            
                System.out.println("unable to delete");
            

            //Thread.sleep(10);
            //writer = null;
            //System.gc();
        
    
    catch(IOException e)
    
        e.printStackTrace();
    
    finally
    
        if(writer != null)
        
            try
            
                writer.close();
            
            catch(IOException e)
            
                e.printStackTrace();
            
        
    

异常发生后,文件不存在。这意味着它正在删除,但 FIleWriter 尝试在此之前获取锁,即使它不是多线程程序。是不是因为 Windows 没有足够快地删除文件,因此 FileWriter 没有获得锁定?如果是这样,那么 file.delete() 方法会在 windows 实际删除它之前返回?

我该如何解决它,因为我在对我的应用程序进行负载测试时遇到了类似的问题。

编辑 1:堆栈跟踪:

java.io.FileNotFoundException: C:\Users\varun.achar\Desktop\TODO.txt (Access is denied)     
at java.io.FileOutputStream.openAppend(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:192)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:116)
    at java.io.FileWriter.<init>(FileWriter.java:61)

EDIT 2:在程序中添加了 file.exists() 和 file.delete 条件。和新的堆栈跟踪:

7452
java.io.FileNotFoundException: C:\Users\varun.achar\Desktop\TODO.txt (Access is denied)
    at java.io.FileOutputStream.openAppend(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:192)
    at java.io.FileWriter.<init>(FileWriter.java:90)
    at com.TestClass.main(TestClass.java:25)

编辑 3 线程转储

TestClass [Java Application]    
    com.TestClass at localhost:57843    
        Thread [main] (Suspended (exception FileNotFoundException)) 
            FileOutputStream.<init>(File, boolean) line: 192    
            FileWriter.<init>(File, boolean) line: 90   
            TestClass.main(String[]) line: 24   
    C:\Users\varun.achar\Documents\Softwares\Java JDK\JDK 6.26\jdk\jre\bin\javaw.exe (09-Nov-2011 11:57:34 PM)  

EDIT 4:程序在具有相同操作系统的不同机器上成功运行。现在我如何确保应用程序在部署它的机器上成功运行?

【问题讨论】:

有什么异常,你还想测试什么? Thread.sleep() 似乎有帮助,但我不能将它放入程序中,否则需要一个半世纪才能完成执行。我可以尝试获取锁直到它成功,但是有更好的方法吗? 我会首先尝试检查delete() 的返回值——它总是true 吗?异常是来自writer.close(),还是来自writer.write(),还是在创建writer 时?另外,“获得锁”是什么意思?我在程序中没有看到任何锁。 @VarunAchar 有什么例外?并发布堆栈跟踪。 @Joonas:锁定 FileWriter 以写入文件。 【参考方案1】:

在任何操作系统上,您一次只能拥有一定数量的打开文件/线程。你似乎达到了你的操作系统限制。尝试在循环内将 file 设置为 null。

【讨论】:

file = null; writer = null; System.gc(); 解决了这个问题。 System.gc() 至关重要。 嗯... 将文件和写入器变量设置为 null 不会改变任何内容,因为当您退出循环(转到下一个文件)时它们将超出范围。而 System.gc() 只是 JVM 执行垃圾收集的一个建议,它不保证它会做任何事情。所以这不是一个合适的解决方案,抱歉。【参考方案2】:

如果我正确理解了您的堆栈跟踪,则尝试创建新的FileWriter 时会出现异常。不进一步调查是不可能知道原因的。

返回值可能会说明一些问题。特别是检查File.delete() 返回的内容。 在尝试创建新的 FileWriter 之前,请检查 File.exists() 返回的内容。

如果之前的delete()在单线程程序中返回true,而exists()紧随其后也返回true,那么这确实很奇怪。

编辑: 所以看来删除成功了,之后文件就不存在了。当然,它应该如何工作,所以FileWriter 抛出异常的原因很奇怪。再想一想,尝试检查File.getParentFile().canWrite()。也就是说,您写入目录的权限是否会以某种方式消失。

编辑 2:

不要在具有相同操作系统的不同机器上遇到错误。现在我如何确保此错误不会出现在将要部署它的应用程序中?

到目前为止,您有 一个 机器工作不正常,而 一个 机器工作正常。也许你可以在更多的机器上试一试。第一台机器可能以某种方式损坏并导致错误。令人惊讶的是,数字计算机及其程序(我的意思是操作系统和 Java,不一定是您的程序)可能只是“有点损坏”,因此它们几乎始终可以完美地工作,但在某些特定硬件上随机失败& 用例 - 通常在重负载下 - 类似于不正确的多线程程序的行为方式。你的问题不一定是你的错:-)

坦率地说,确保在机器 X 上不会出现错误的唯一方法是在机器 X 上运行程序。不寻常的事情,例如创建和删除同一个文件 8000 次快速继承容易出错,即使它“应该”起作用。计算机、操作系统和 API 并不完美。你做的不寻常的事情越多,缺陷就会越多地显现出来,因为不寻常的使用通常没有日常操作那么彻底地测试。

【讨论】:

不。 if(!file.getParentFile().canWrite()) System.out.println("parent file error"); 不执行。【参考方案3】:

我遇到了同样的问题,一个 java 程序(单线程)打开,删除然后不断地重新打开同一个文件。

在某些 Windows 系统上,我们遇到了与此处报告的问题相同的问题,在 Linux、Solaris 和各种其他 Windows 系统上它工作正常。

使用SysInternals Process Monitor (now MS) 跟踪程序,它首先在操作系统级别清除删除,并清除后续打开失败并显示 PENDING DELETE 状态。

因此,在实际删除文件之前,OS/NTFS/磁盘级别似乎有一些轻微的延迟,这似乎是我们案例中随机失败的原因。

作为一种解决方法,我将 .delete() 调用更改为仅在其顶部写入 new FileWriter(file) ,这似乎可以正常工作。

该问题并非在所有系统上都出现,一种总是会失败的特定型号,无论是在没有固定数量的循环之后,都是带有 WD Smartdrive 的 Windows 7 / Dell Lattitude E6420,而我的 Windows 7 / Dell Precision M4600 (带有固态驱动器)或带有 Linux 的 T3400 我从来没有遇到过这个问题。

干杯 - 马克

【讨论】:

【参考方案4】:

这可能是一个长镜头,但是,您可以尝试使用不直接位于桌面上的文件吗?而不是:

"C:\\Users\\varun.achar\\Desktop\\TODO.txt"

试试:

"C:\\Users\\varun.achar\\SomeOtherDirectory\\TODO.txt"

操作系统可能在这里用所有桌面挂钩杀死你......

根据 cmets 进行编辑:

是否有任何计划作业在“坏”机器上运行? 您是否有系统管理员来调试环境而不是调试环境? 这是否适用于 clean Windows 安装? [95% 的几率] 由于根本原因似乎是环境问题,而不是解决 Windows 配置问题,您是否能够继续执行其他任务,并将其留给保存系统之间差异列表的人?

【讨论】:

我的应用程序正在写入的实际文件位于其他目录中。该程序只是重新创建错误。 我刚刚在 OS/X 上运行它 => 运行良好。即使有 10 万次迭代。 (java版本“1.6.0_26”)。我仍然会尝试将目录更改为 ELSE 并重试。 你能在不同的操作系统、不同的物理机上试试吗? (你可以使用VirtualBox 或者只是在安装 Java 的地方使用 ssh) 不要在具有相同操作系统的不同机器上出现错误。现在我如何确保此错误不会出现在将要部署它的应用程序中?【参考方案5】:

你能有条件地尝试写入文件吗?

使用 file.exists 然后写入它,因此您可以潜在地避免任何其他问题。这个例外很难说。

http://download.oracle.com/javase/6/docs/api/java/io/File.html#exists()

您是否也可以在那时发布一个线程转储,只是为了进一步调试它。

请在再次写入之前刷新写入器。

【讨论】:

没有帮助。 if(!file.delete()) 之后的行不执行。在创建 FileWriter 之前存在的 if(file.exists()) 也不存在 好的,请每次刷新writer,应该可以解决。也在更新答案。 根据文档,close() 关闭流,首先刷新它。所以显式刷新在这里应该没有区别。【参考方案6】:

这些是您在删除文件http://www.java2s.com/Code/Java/File-Input-Output/DeletefileusingJavaIOAPI.htm之前应该处理的场景

至少检查程序中的返回值。

【讨论】:

没有帮助。 if(!file.delete()) 之后的行不执行。在创建 FileWriter 之前存在的 if(file.exists()) 也不存在 尝试一些奇怪的东西。更改文件位置后尝试相同的程序并更改文件名。 每次异常发生后的迭代次数是否也相同? 当您遇到异常时,请尝试在 catch 块中再次创建 FileWriter。同名也不同。【参考方案7】:

感谢大家帮助我,但这就是最终解决的方法。

public static void main(String[] args)
    
        FileWriter writer = null;
        try
        
            for(int i = 0; i < 10000; i++)
            
                File file = new File("C:\\tenant-system-data\\abc.txt");
                if(!file.getParentFile().canWrite())
                
                    System.out.println("parent file error");
                
                if(file.exists())
                
                    System.out.println("File exists");
                
                int count = 0;
                while(count++ < 5)
                
                    try
                    
                        file.createNewFile();
                        break;
                    
                    catch(IOException e)
                    
                        try
                        
                            Thread.sleep(100);
                        
                        catch(InterruptedException e1)
                        
                            e1.printStackTrace();
                        

                    
                
                writer = new FileWriter(file, true);
                writer.write(i);
                System.out.println(i);
                writer.close();
                if(!file.delete())
                
                    System.out.println("unable to delete");
                

                //Thread.sleep(10);
                //writer = null;
                //System.gc();
            
        
        catch(IOException e)
        
            e.printStackTrace();
        
        finally
        
            if(writer != null)
            
                try
                
                    writer.close();
                
                catch(IOException e)
                
                    e.printStackTrace();
                
            
        
    

【讨论】:

【参考方案8】:

我也遇到了同样的问题(FileWriter & Access Denied)。

我的猜测原因是:Windows 7 锁定了文件,因为文件内容的预览显示在资源管理器窗口中(在窗口中选择了文件)。

解决方案:我在资源管理器窗口中取消选择该文件。并且 IOException 消失了。

【讨论】:

这应该是一条评论。【参考方案9】:

您在目录中有删除权限,但没有创建权限。

【讨论】:

第 8000 次迭代中出现错误,这意味着它正在删除和创建前 8000 次以上。 @VarunAchar 如果您真的在一个会话中创建 > 8,000 个文件,我会质疑您的设计。您应该使用数据库。 没有真正创建 8000 个文件.. 一个文件被一遍又一遍地创建和删除。我这样做是为了实际填充我的数据库以进行负载测试。该文件用作 DB 故障转移功能,以保持 DB 和 lucene 之间的状态一致。

以上是关于java.io 上的 FileNotFound(访问被拒绝)异常的主要内容,如果未能解决你的问题,请参考以下文章

getInputStream() 上的 java.io.FileNotFoundException

Android上的java.io.FileNotFoundException,打开失败:ENOENT(没有这样的文件或目录)

Windows 上的 Hudson - 错误:java.io.IOException:无法运行程序“sh”

WSL 上的齐柏林飞艇。 java.io.IOException:无法启动解释器进程

抛出 java.io.IOException: 当我尝试从服务器下载 txt 文件时,http:/ 上的流意外结束

java.io.IOException:流已重置:多个设备上的 REFUSED_STREAM