You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

java.nio.file.AccessDeniedException异常:图片读取权限问题排查

排查读取图片时的AccessDeniedException异常

先梳理下你的问题场景:你用这段代码把Base64编码的图片存储到项目路径中:

if(imgString != null ) { 
    BufferedImage image = null; 
    byte[] imageByte; 
    BASE64Decoder decoder = new BASE64Decoder(); 
    imageByte = decoder.decodeBuffer(imgString); 
    ByteArrayInputStream bis = new ByteArrayInputStream(imageByte); 
    image = ImageIO.read(bis); 
    bis.close(); 
    String realPath = request.getSession().getServletContext().getRealPath("/resources/images/"+studentDetails.getFirstname()+".png"); 
    File outputfile = new File(realPath); 
    ImageIO.write(image, "png", outputfile); 
    studentDetails.setStuImg(outputfile.toString()); 
}

但之后用下面的代码读取该图片时,在Files.readAllBytes这一行抛出了AccessDeniedException:

if(imagePath != null) { 
    byte[] bytes = Files.readAllBytes(Paths.get(imagePath)); // 异常抛出点
    encodedFile = Base64.getEncoder().encodeToString(bytes); 
}

对应的异常栈迹如下:

java.nio.file.AccessDeniedException: 
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source) 
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source) 
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source) 
at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(Unknown Source) 
at java.nio.file.Files.newByteChannel(Unknown Source) 
at java.nio.file.Files.newByteChannel(Unknown Source) 
at java.nio.file.Files.readAllBytes(Unknown Source) 
at com.rasvek.cms.controller.StudentController.getStudentAdmissionByAdmissionId(StudentController.java:510) 
at com.rasvek.cms.controller.StudentController$$FastClassBySpringCGLIB$$cb2af793.invoke(<generated>) 
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) 
at com.rasvek.cms.controller.StudentController$$EnhancerBySpringCGLIB$$537bb5b8.getStudentAdmissionByAdmissionId(<generated>) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
at java.lang.reflect.Method.invoke(Unknown Source) 
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) 
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) 
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) 
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) 
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) 
at org.apache.catalina.core.StandardContextVa

可能的原因分析

  1. Tomcat运行用户权限不足
    这是最常见的原因:你的Tomcat进程是用某个用户身份启动的,而这个用户没有读取目标图片文件或其父目录的权限。比如在Windows下,你用自己的账号开发时创建了文件,但Tomcat作为系统服务运行时用的是Local System或者其他受限账号,没有访问该文件的权限。

  2. 文件被其他进程锁定
    存储图片后,可能有其他程序(比如图片预览工具、杀毒软件)锁定了这个文件,导致Java进程无法打开读取。

  3. getRealPath()的路径局限性
    getRealPath()返回的是Web应用在服务器上的临时部署路径,在IDE内嵌Tomcat和生产环境独立Tomcat中路径可能不同,甚至容器重启后路径会变化。如果存储时的路径和读取时的路径不一致,也可能触发权限类的异常(虽然更常见的是文件不存在,但也有可能因为路径对应的目录权限问题报错)。

  4. 存储时文件权限未正确设置
    创建文件时,默认的权限设置可能仅允许创建文件的用户(比如你的开发账号)访问,而Tomcat运行用户不在权限范围内。


对应的解决方案

1. 检查并调整文件/目录权限

  • 先确认图片的实际存储路径:在存储代码中添加System.out.println(realPath);,打印出文件的绝对路径。
  • 找到该文件,右键打开属性→安全选项卡,添加Tomcat运行的用户账号(比如Local System或者你自定义的服务账号),并赋予它读取权限。
  • 同时检查父目录(比如resources/images/)的权限,确保该用户能遍历目录并访问其中的文件。

2. 替换getRealPath(),使用外部固定目录存储

getRealPath()依赖Web应用的部署路径,稳定性差,建议改用一个固定的外部目录来存储图片,比如D:/student_images/:

if(imgString != null ) { 
    BufferedImage image = null; 
    byte[] imageByte; 
    BASE64Decoder decoder = new BASE64Decoder(); 
    imageByte = decoder.decodeBuffer(imgString); 
    ByteArrayInputStream bis = new ByteArrayInputStream(imageByte); 
    image = ImageIO.read(bis); 
    bis.close(); 

    // 改用外部固定目录
    String externalImageDir = "D:/student_images/";
    File dir = new File(externalImageDir);
    // 确保目录存在,不存在则创建
    if (!dir.exists()) {
        dir.mkdirs();
    }
    String filePath = externalImageDir + studentDetails.getFirstname() + ".png";
    File outputfile = new File(filePath); 
    ImageIO.write(image, "png", outputfile); 
    studentDetails.setStuImg(filePath); 
}

读取时直接使用这个外部路径即可,同时给D:/student_images/目录设置好Tomcat运行用户的读写权限。

3. 释放文件锁

关闭所有可能打开该图片的程序(比如Windows照片查看器),或者重启Tomcat服务,释放文件锁后再尝试读取。

4. 显式设置文件权限(可选)

在创建文件后,可以通过代码显式设置文件的可读权限,不过这个方法在不同操作系统下兼容性有限,更推荐直接调整系统目录权限:

// 写入图片后添加
outputfile.setReadable(true, false); // 第二个参数为false表示所有用户都可读
outputfile.setWritable(true, false); // 如果需要后续修改也可以加上

5. 验证路径一致性

在读取代码中添加System.out.println(imagePath);,对比存储时打印的路径,确保两者完全一致,避免因为路径拼写错误或环境变更导致读取错误的文件。

内容的提问来源于stack exchange,提问作者bharath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:37