javax异常: javax.imageio.IIOException: Can't create output stream解决方法

  • 验证码工具类:

 
1
package com.newcapec.utils;
2
3
import com.sun.image.codec.jpeg.JPEGCodec;
4
import com.sun.image.codec.jpeg.JPEGImageEncoder;
5
6
import java.awt.*;
7
import java.awt.image.BufferedImage;
8
import java.io.FileOutputStream;
9
import java.io.IOException;
10
import java.io.OutputStream;
11
import java.util.Random;
12
13
/** 
14
 * 

Title: ValidateCode.java

 
15
 * 

Description: 验证码工具类

 
16
 */
17
public class ValidateCode {    
18
    // 图片的宽度。  
19
    private int width = 120;  
20
    // 图片的高度。  
21
    private int height = 40;  
22
    // 验证码字符个数  
23
    private int codeCount = 4;  
24
    // 验证码干扰线数  
25
    private int lineCount = 30;  
26
    // 验证码  
27
    private String code = null;  
28
    // 验证码图片Buffer  
29
    private BufferedImage buffImg = null;  
30
  
31
    private char[] codeSequence = { 'A','a', 'B','b', 'C','c', 'D','d', 'E','e', 'F','f', 'g','H','h',  
32
            'J','j', 'K','k','L', 'M','m', 'N','n', 'P','p', 'Q','q', 'R','r', 'S','s', 'T', 'U','u', 'V', 'W','w',  
33
            'X','x', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};  
34
  
35
    // 生成随机数  
36
    private Random random = new Random();  
37
  
38
    public ValidateCode() {  
39
        this.createCode();  
40
    }  
41
  
42
    /** 
43
     *  
44
     * @param width 
45
     *            图片宽 
46
     * @param height 
47
     *            图片高 
48
     */  
49
    public ValidateCode(int width, int height) {  
50
        this.width = width;  
51
        this.height = height;  
52
        this.createCode();  
53
    }  
54
  
55
    /** 
56
     *  
57
     * @param width 
58
     *            图片宽 
59
     * @param height 
60
     *            图片高 
61
     * @param codeCount 
62
     *            字符个数 
63
     * @param lineCount 
64
     *            干扰线条数 
65
     */  
66
    public ValidateCode(int width, int height, int codeCount, int lineCount) {  
67
        this.width = width;  
68
        this.height = height;  
69
        this.codeCount = codeCount;  
70
        this.lineCount = lineCount;  
71
        this.createCode();  
72
    }  
73
  
74
    public void createCode() {  
75
        Random heightRandom = new Random();
76
        int codeX = 0;  
77
        int fontHeight = 0;  
78
        fontHeight = height-heightRandom.nextInt(7)-7;// 字体的高度  
79
        codeX = width / (codeCount+1);// 每个字符的宽度  
80
  
81
        // 图像buffer  
82
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
83
        Graphics2D g = buffImg.createGraphics();  
84
  
85
        // 将图像填充为白色  
86
        g.setColor(Color.WHITE);  
87
        g.fillRect(0, 0, width, height);  
88
  
89
        // 创建字体  
90
        ImgFontByte imgFont = new ImgFontByte();  
91
        Font font = imgFont.getFont(fontHeight);  
92
        g.setFont(font);  
93
  
94
        // 绘制干扰线  
95
        for (int i = 0; i < lineCount; i++) {  
96
            int xs = getRandomNumber(width);  
97
            int ys = getRandomNumber(height);  
98
            int xe = xs + getRandomNumber(width / 8);  
99
            int ye = ys + getRandomNumber(height / 8);  
100
            g.setColor(getRandomColor());  
101
            g.drawLine(xs, ys, xe, ye);  
102
        }  
103
  
104
        
105
        StringBuffer randomCode = new StringBuffer();  
106
        
107
//        int x = 5;
108
        // 随机产生验证码字符  
109
        for (int i = 0; i < codeCount; i++) {
110
            int h = height-8;
111
            int w = (i + 1) * codeX+heightRandom.nextInt(4);
112
            String strRand = String.valueOf(codeSequence[random  
113
                    .nextInt(codeSequence.length)]);  
114
            // 设置字体颜色  
115
            g.setColor(getRandomColor());  
116
117
            int degree = new Random().nextInt() % 10;
118
            g.rotate(degree * Math.PI / 180,(w+codeX-5)/2, (h+fontHeight)/2);
119
            // 设置字体位置  
120
            g.drawString(strRand, w, h );  //getRandomNumber(height / 2) + 25
121
            g.rotate(-degree * Math.PI / 150, (w+codeX-5)/2, (h+fontHeight)/2);
122
            randomCode.append(strRand);  
123
        }  
124
        code = randomCode.toString();  
125
    }  
126
  
127
    /** 获取随机颜色 */  
128
    private Color getRandomColor() {  
129
        int r = getRandomNumber(225);  
130
        int g = getRandomNumber(225);  
131
        int b = getRandomNumber(225);  
132
        return new Color(r, g, b);  
133
    }
134
  
135
    /** 获取随机数 */  
136
    private int getRandomNumber(int number) {  
137
        return random.nextInt(number);  
138
    }  
139
  
140
    public void write(String path) throws IOException {  
141
        OutputStream sos = new FileOutputStream(path);  
142
        this.write(sos);  
143
    }  
144
  
145
    public void write(OutputStream sos) throws IOException {  
146
//         ImageIO.write(buffImg, "png", sos);
147
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(sos);
148
        encoder.encode(buffImg);
149
        sos.close();  
150
    }  
151
  
152
    public BufferedImage getBuffImg() {  
153
        return buffImg;  
154
    }  
155
  
156
    public String getCode() {  
157
        return code;  
158
    }  
159
  
160
    /** 字体样式类 */  
161
    class ImgFontByte {
162
        public Font getFont(int fontHeight) {  
163
            return new Font("Arial", Font.PLAIN, fontHeight);
164
        }  
165
    }  
166
    
167
    
168
}
169

  • 使用
 
1
public void scaptcha(){
2
        HttpServletResponse response = ServletActionContext.getResponse();
3
        response.reset();
4
        // 设置响应的类型格式为图片格式  
5
        response.setContentType("image/jpeg");  
6
        // 禁止图像缓存。  
7
        response.setHeader("Pragma", "no-cache");  
8
        response.setHeader("Cache-Control", "no-cache");  
9
        response.setDateHeader("Expires", 0);  
10
        ValidateCode instance = new ValidateCode();
11
        CookieUtil.setCookie(response, "scaptcha", instance.getCode().toUpperCase(), null, -1);
12
        try {
13
            instance.write(response.getOutputStream());
14
        } catch (IOException e) {
15
            e.printStackTrace();
16
        }
17
    }


在使用ImageIO.write时,发现在Linux平台上,会出现异常:

 
1
javax.imageio.IIOException: Can't create output stream
 
1
检查tomcat的日志,终于真相大白:
2
3
javax.imageio.IIOException: Can't create output stream!
4
5
 at javax.imageio.ImageIO.write(ImageIO.java:1521)
6
7
Caused by: javax.imageio.IIOException: Can't create cache file!
8
9
 at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:395)
10
11
 at javax.imageio.ImageIO.write(ImageIO.java:1519)
12
13
 ... 34 more
14
Caused by: java.io.IOException: 系统找不到指定的路径。
15
16
原来是ImageIO.write(image, "jpeg", response.getOutputStream());


查看日志,发现是由找不到文件引起

 
1
Java.nio.file.NoSuchFileException: xxx.../temp/imageio4138671232726624650.tmp


  • 主要原因如下:

在使用ImageIO进行图片写操作时,默认会使用缓存目录:${tomcat}/temp,在此缓存目录会生成缓存文件imageio4138671232726624650.tmp(这一串数字应该是当前时间戳,临时文件名),有些生产环境的tomcat,会将temp目录删除,因此报错


  • 4种解决方法如下:

    1. 在tomcat下新建temp目录; 
    2. 与方法1相似,通过ImageIO.setCacheDirectory(cacheDirectory);设置任意的、存在的缓存目录
    3. ImageIO默认是使用缓存目录,可以通过ImageIO.setUseCache(false)来设置,更改缓存策略,不使用文件目录缓存,使用内存缓存
    4. 不使用ImageIO,换成其它JDK方法
 
1
ImageIO.write(bi, "jpg", baos);
2
换成:
3
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(response.getOutputStream()); 
4
encoder.encode(image);

你可能感兴趣的:(javax异常,回归JAVA)