javax.imageio.IIOException: Can't create output stream!


      我一直使用POI给Excel写图片ImageIO.write(bufferImg, pictureFormat, byteArrayOut);,今天遇见一个奇葩的问题,导出这个Excel在本地一直都是好的,课时到了正式的Linux的环境下,却打死都倒不出来。

javax.imageio.IIOException: Can't create output stream! javax.imageio.ImageIO.write(ImageIO.java:1521) 
org.apache.jsp.images_jsp._jspService(images_jsp.java:126) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
 javax.servlet.http.HttpServlet.service(HttpServlet.java:802) 
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324) 
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
 org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236) 
javax.servlet.http.HttpServlet.service(HttpServlet.java:802) 
org.extremecomponents.table.filter.AbstractExportFilter.doFilter(AbstractExportFilter.java:49)
</pre><p></p><pre name="code" class="java">javax.imageio.IIOException: Can't create output stream!
 at javax.imageio.ImageIO.write(ImageIO.java:1521)
 at org.apache.jsp.images_jsp._jspService(images_jsp.java:126)
 at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
 at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)
 at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
 at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
 at org.extremecomponents.table.filter.AbstractExportFilter.doFilter(AbstractExportFilter.java:49)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
 at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
 at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
 at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
 at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
 at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
 at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
 at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
 at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
 at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
 at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
 at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
 at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
 at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
 at java.lang.Thread.run(Thread.java:595)
Caused by: javax.imageio.IIOException: Can't create cache file!
 at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:395)
 at javax.imageio.ImageIO.write(ImageIO.java:1519)
 ... 34 more
Caused by: java.io.IOException: 系统找不到指定的路径。
 at java.io.WinNTFileSystem.createFileExclusively(Native Method)
 at java.io.File.checkAndCreate(File.java:1345)
 at java.io.File.createTempFile(File.java:1434)
 at javax.imageio.stream.FileCacheImageOutputStream.<init>(FileCacheImageOutputStream.java:67)
 at com.sun.imageio.spi.OutputStreamImageOutputStreamSpi.createOutputStreamInstance(OutputStreamImageOutputStreamSpi.java:50)
 at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:391)
 ... 35 more

原来是ImageIO.write(image, "jpeg", response.getOutputStream());
需要写缓冲文件,但是写文件不成功。



解决办法

1.可以 修改程序 

把 ImageIO.write(image, "jpeg", response.getOutputStream());
修改为
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(response.getOutputStream());
encoder.encode(image);

2.tomcat 的temp 目录必须有
为什么 ImageIO.write 这种方式 需要 temp 目录 呢?

带着疑问,看看源码(Java的开源好处真心不错) :

Java代码   收藏代码
  1. public static ImageOutputStream <strong>createImageOutputStream</strong>(Object output)  
  2.     throws IOException {  
  3.     if (output == null) {  
  4.         throw new IllegalArgumentException("output == null!");  
  5.     }  
  6.   
  7.     Iterator iter;  
  8.     // Ensure category is present  
  9.     try {  
  10.         iter = theRegistry.getServiceProviders(ImageOutputStreamSpi.class,  
  11.                                                true);  
  12.     } catch (IllegalArgumentException e) {  
  13.         return null;  
  14.     }  
  15.   
  16.     boolean usecache =<strong> getUseCache() && hasCachePermission()</strong>;  
  17.   
  18.     while (iter.hasNext()) {  
  19.         ImageOutputStreamSpi spi = (ImageOutputStreamSpi)iter.next();  
  20.         if (spi.getOutputClass().isInstance(output)) {  
  21.             try {  
  22.                 return spi.createOutputStreamInstance(output,  
  23.                                                       usecache,  
  24.                                                       <strong>getCacheDirectory()</strong>);  
  25.             } catch (IOException e) {  
  26.                 throw new IIOException("Can't create cache file!", e);  
  27.             }  
  28.         }  
  29.     }  
  30.   
  31.     return null;  
  32. }  
 

会调用 cache 文件夹 ,他所谓的cache 文件夹是怎么样定义的呢?


Java代码   收藏代码
  1. private static boolean hasCachePermission() {  
  2.     Boolean hasPermission = getCacheInfo().getHasPermission();  
  3.   
  4.     if (hasPermission != null) {  
  5.         return hasPermission.booleanValue();  
  6.     } else {  
  7.         try {  
  8.             SecurityManager security = System.getSecurityManager();  
  9.             if (security != null) {  
  10.                 File cachedir = getCacheDirectory();  
  11.                 String cachepath;  
  12.   
  13.                 if (cachedir != null) {  
  14.                     cachepath = cachedir.getPath();  
  15.                 } else {  
  16.                     cachepath = getTempDir();  
  17.   
  18.                     if (cachepath == null) {  
  19.                         getCacheInfo().setHasPermission(Boolean.FALSE);  
  20.                         return false;  
  21.                     }  
  22.                 }  
  23.   
  24.                 security.checkWrite(cachepath);  
  25.             }  
  26.         } catch (SecurityException e) {  
  27.             getCacheInfo().setHasPermission(Boolean.FALSE);  
  28.             return false;  
  29.         }  
  30.   
  31.         getCacheInfo().setHasPermission(Boolean.TRUE);  
  32.         return true;  
  33.     }  
  34. }  
 

写得也很清楚,如果自己设置了 set CacheDirectory 那么会使用自定义的,否则调用   getTempDir()


Java代码   收藏代码
  1. /** 
  2.   * Returns the default temporary (cache) directory as defined by the 
  3.   * java.io.tmpdir system property. 
  4.   */  
  5.  private static String getTempDir() {  
  6.      GetPropertyAction a = new GetPropertyAction("java.io.tmpdir");  
  7.      return (String)AccessController.doPrivileged(a);  
  8.  }  
 

Oh, 会读取变量java.io.tmpdir!

大家还记得 tomcat 启动的时候,会显示
Java代码   收藏代码
  1. Using CATALINA_BASE:   /home/appuser/appservers/tomcat-feilong  
  2. Using CATALINA_HOME:   /home/appuser/appservers/tomcat-feilong  
  3. Using CATALINA_TMPDIR: /home/appuser/appservers/tomcat-feilong/temp  
  4. Using JRE_HOME:        /usr/lib/jvm/java-6-sun  
  5. Using CLASSPATH:       /home/appuser/appservers/tomcat-feilong/bin/bootstrap.jar  
 
 $CATALINA_TMPDIR 这个变量就是 我们的temp 文件夹 

而tomcat 启动的时候,调用jvm会设置  java.io.tmpdir  参数 

看 

rem    CATALINA_TMPDIR (Optional) Directory path location of temporary directory
rem                   the JVM should use (java.io.tmpdir).  Defaults to
rem                   %CATALINA_BASE%\temp.


 

 

 

%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%


 

 

这下终于弄明白了, ImageIO.write(image, "JPEG", os) 这种方式 来生成图片、验证码 tomcat必须要有temp文件夹的来龙去脉了




要将多页 TIFF 转换成一张图片,你可以使用 Java Advanced Imaging API(JAI)和 Java Image IO API。以下是一个示例代码: ```java import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.plugins.tiff.TIFFImageReadParam; import javax.imageio.plugins.tiff.TIFFImageWriteParam; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; public class TIFFUtils { public static BufferedImage convertToSinglePageTIFF(byte[] tiffBytes) throws IOException { ImageReader reader = ImageIO.getImageReadersByFormatName("TIFF").next(); ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(tiffBytes)); reader.setInput(iis); // Read the first page RenderedOp op = JAI.create("stream", reader); BufferedImage image = op.getAsBufferedImage(); // Write the first page to a new TIFF file ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream); writer.setOutput(ios); TIFFImageWriteParam writeParam = (TIFFImageWriteParam) writer.getDefaultWriteParam(); writeParam.setCompressionMode(TIFFImageWriteParam.MODE_DEFAULT); writeParam.setCompressionType("LZW"); IIOMetadata metadata = writer.getDefaultImageMetadata(reader.getImageTypes(0).next(), writeParam); writer.write(metadata, new javax.imageio.IIOImage(image, null, metadata), writeParam); // Write the rest of the pages to the new TIFF file for (int i = 1; i < reader.getNumImages(true); i++) { op = JAI.create("stream", reader); image = op.getAsBufferedImage(); writer.write(null, new javax.imageio.IIOImage(image, null, null), writeParam); } writer.dispose(); ios.close(); iis.close(); // Read the new TIFF file and return the image byte[] singlePageTiffBytes = outputStream.toByteArray(); reader = ImageIO.getImageReadersByFormatName("TIFF").next(); iis = ImageIO.createImageInputStream(new ByteArrayInputStream(singlePageTiffBytes)); reader.setInput(iis); op = JAI.create("stream", reader); BufferedImage singlePageImage = op.getAsBufferedImage(); reader.dispose(); iis.close(); return singlePageImage; } } ``` 这个方法接受一个多页 TIFF 的字节数组作为输入,并返回一个合并后的 BufferedImage。它首先使用 Java Image IO API 读取多页 TIFF,然后将每个页面写入一个新的单页 TIFF 文件。接下来,它使用 Java Image IO API 读取新的单页 TIFF 文件,并返回合并后的 BufferedImage。 希望这可以帮到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值