java.io.IOException:Stream已关闭

对于多个图像检索,我调用带有锚标记的PhotoHelperServlet来获取imageNames(多个图像),如下所示

PhotoHelperServlet获取Images名称

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Getting userid from session Image image = new Image(); image.setUserid(userid); ImageDAO imageDAO = new ImageDAO(); try { List imageId = imageDAO.listNames(image); if (imageId == null) { // check if imageId is retreived } request.setAttribute("imageId", imageId); //Redirect it to home page RequestDispatcher rd = request.getRequestDispatcher("/webplugin/jsp/profile/photos.jsp"); rd.forward(request, response); catch (Exception e) { e.printStackTrace(); } 

在ImageDAO listNames()方法中:

 public List listNames(Image image) throws IllegalArgumentException, SQLException, ClassNotFoundException { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultset = null; Database database = new Database(); List imageId = new ArrayList(); try { connection = database.openConnection(); preparedStatement = connection.prepareStatement(SQL_GET_PHOTOID); preparedStatement.setLong(1, image.getUserid()); resultset = preparedStatement.executeQuery(); while(resultset.next()) { image.setPhotoid(resultset.getLong(1)); imageId.add(image); } } catch (SQLException e) { throw new SQLException(e); } finally { close(connection, preparedStatement, resultset); } return imageId; } 

在JSP代码中:

    

在PhotoServlet doGet()方法中获取照片:

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String imageid = request.getPathInfo().substring(1); if(imageid == null) { // check for null and response.senderror } ImageDAO imageDAO = new ImageDAO(); try { Image image = imageDAO.getPhotos(imageid); if(image == null) {} BufferedInputStream input = null; BufferedOutputStream output = null; try { input = new BufferedInputStream(image.getPhoto(), DEFAULT_BUFFER_SIZE); output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE); // Write file contents to response. byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; int length; while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } } finally { if (output != null) try { output.close(); } catch (IOException logOrIgnore) {} if (input != null) try { input.close(); } catch (IOException logOrIgnore) {} } } catch(Exception e) { e.printStackTrace(); } 

在ImageDAO getPhotos()方法中

 public Image getPhotos(String imageid) throws IllegalArgumentException, SQLException, ClassNotFoundException { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultset = null; Database database = new Database(); Image image = new Image(); try { connection = database.openConnection(); preparedStatement = connection.prepareStatement(SQL_GET_PHOTO); preparedStatement.setString(1, imageid); resultset = preparedStatement.executeQuery(); while(resultset.next()) { image.setPhoto(resultset.getBinaryStream(1)); } } catch (SQLException e) { throw new SQLException(e); } finally { close(connection, preparedStatement, resultset); } return image; } 

在web.xml中

   Photos Module app.controllers.PhotoServlet   Photos Module /Photos/*    Photo Module app.controllers.PhotoHelperServlet   Photo Module /Photo  

题:

我得到以下例外:

 java.io.IOException: Stream closed 

在这条线上:

 at app.controllers.PhotoServlet.doGet(PhotoServlet.java:94) while ((length = input.read(buffer)) > 0) { 

完整例外:

 java.io.IOException: Stream closed at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:134) at java.io.BufferedInputStream.read1(BufferedInputStream.java:256) at java.io.BufferedInputStream.read(BufferedInputStream.java:317) at java.io.FilterInputStream.read(FilterInputStream.java:90) at app.controllers.PhotoServlet.doGet(PhotoServlet.java:94) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:498) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:394) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) 

我想象的基本代码流程如下:

 try { Get connection, statement, resultset Use connection, statement, resultset Get inputstream of resultset } finally { Close resultset, statement, connection } try { Get outputstream Use inputstream of resultset, outputstream } finally { Close outputstream, inputstream of resultset } 

并且ResultSet的关闭隐式关闭了InputStream 。 看起来,当ResultSet关闭时,JDBC驱动程序不会将ResultSetInputStream完全存储在内存或临时存储中。 也许JDBC驱动程序有点简单,或者没有深思熟虑,或者图像太大而无法存储在内存中。 谁知道。

我首先要弄清楚您正在使用的JDBC驱动程序impl / version,然后查阅其开发人员文档以了解可能能够更改/修复此行为的设置。 如果你仍然无法弄明白,那么你必须重新安排基本代码流程如下:

 try { Get connection, statement, resultset Use connection, statement, resultset try { Get inputstream of resultset, outputstream Use inputstream of resultset, outputstream } finally { Close outputstream, inputstream of resultset } } finally { Close resultset, statement, connection } 

要么

 try { Get connection, statement, resultset Use connection, statement, resultset Get inputstream of resultset Copy inputstream of resultset } finally { Close resultset, statement, connection } try { Get outputstream Use copy of inputstream, outputstream } finally { Close outputstream, copy of inputstream } 

第一种方法是最有效的,只有代码是笨拙的。 当您复制到ByteArrayOutputStream ,第二种方法是内存效率低,或者当您复制到FileOutputStream时性能效率低下。 如果图像大多数小并且不超过兆字节或其他东西,那么我只需将其复制到ByteArrayOutputStream

 InputStream input = null; OutputStream output = null; try { input = new BufferedInputStream(resultSet.getBinaryStream("columnName"), DEFAULT_BUFFER_SIZE); output = new ByteArrayOutputStream(); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; for (int length; ((length = input.read(buffer)) > 0;) { output.write(buffer, 0, length); } } finally { if (output != null) try { output.close(); } catch (IOException ignore) {} if (input != null) try { input.close(); } catch (IOException ignore) {} } Image image = new Image(); image.setPhoto(new ByteArrayInputStream(output.toByteArray())); // ... 
  参考一下: ImageLoad import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.ImageSwitcher; import android.widget.ImageView; /** * 图片加载帮助类(自动异步加载、图片文件缓存、缓存文件管理) * * @author n.zhang * */ public class ImageLoad { private static final String TAG = "imageLoad";// 日志标签private static final String TAG_REF = TAG + "Ref"; private Executor executor; // 线程池private int defaultImageID;// 默认图片id private Context context;// 你懂的private HashMap cache = new HashMap();// URL boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 路径信息对应表private LinkedList use = new LinkedList();// 已在使用的路径信息队列private LinkedList lost = new LinkedList();// 还未使用的路径信息队列private LinkedList original = new LinkedList();// 初始图片路径信息队列private int index = 0;// id下标/** * 图片加载工具,默认10线程下载,缓存80张图片* * @param context */ public ImageLoad(Context context) { this(context, 10, 80, 0); } /** * 图片加载工具* * @param context * 你懂的* @param threadSize * 最大线程数* @param maxCacheSize * 最大缓存图片数量* @param defaultImageID * 默认图片id */ public ImageLoad(Context context, int threadSize, int maxCacheSize, int defaultImageID) { this.context = context; this.defaultImageID = defaultImageID; executor = Executors.newFixedThreadPool(threadSize); loadImagePathInfo(); // 图片信息数量不足不满最大值,以空白图片信息补足。 newImagePathInfo(maxCacheSize); for (PathInfo pi : original) { if (null == pi.url) { lost.offer(pi); } else { use.offer(pi); cache.put(pi.url, pi); } } File dir = null; if (sdCardExist) { dir = new File(Environment.getExternalStorageDirectory() + "/t_image/"); } else { dir = new File(context.getCacheDir() + "/t_image/"); } // 如果文件存在并且不是目录,则删除if (dir.exists() && !dir.isDirectory()) { dir.delete(); } // 如果目录不存在,则创建if (!dir.exists()) { dir.mkdir(); } } /** * 路径信息* * @author n.zhang * */ public static class PathInfo { private int id;// 图片id 此id用于生成存储图片的文件名。 private String url;// 图片url } /** * 获得图片存储路径* * @param url * @return */ public PathInfo getPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.poll(); } if (null == pc) { pc = use.poll(); refresh(pc); } return pc; } /** * @info 微博使用加载数据路径* @author FFMobile-cuihe * @date 2012-3-1 下午2:13:10 * @Title: getsPath * @Description: TODO * @param@param url * @param@return 设定文件* @return PathInfo 返回类型* @throws */ public PathInfo getsPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.peek(); } // if (null == pc) { // pc = use.peek(); // refresh(pc); // } return pc; } public PathInfo getLocalPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.peek(); } return pc; } /** * 刷新路径信息(从索引中删除对应关系、删除对应的图片文件、获取一个新id) * * @param pc */ private void refresh(PathInfo pc) { long start = System.currentTimeMillis(); File logFile = null; try { cache.remove(pc.url); File file = toFile(pc); file.delete(); logFile = file; pc.id = index++; pc.url = null; } finally { Log.d(TAG_REF, "ref time {" + (System.currentTimeMillis() - start) + "}; ref {" + logFile + "}"); } } /** * 获得file对象* * @param pi * 路径缓存* @return */ public File toFile(PathInfo pi) { if (sdCardExist) { return new File(Environment.getExternalStorageDirectory() + "/t_image/" + pi.id + ".jpg"); } else { return new File(context.getCacheDir() + "/t_image/" + pi.id + ".jpg"); } } /** * 请求加载图片* * @param url * @param ilCallback */ public void request(String url, final ILCallback ilCallback) { final long start = System.currentTimeMillis(); final PathInfo pc = getPath(url); File file = toFile(pc); if (null != pc.url) { ilCallback.seed(Uri.fromFile(file)); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; cache {" + pc.url + "} "); } else { pc.url = url; Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (null == msg.obj) { ilCallback.seed(Uri.EMPTY); Log.d(TAG, "load lost time {" + (System.currentTimeMillis() - start) + "}; network lost {" + pc.url + "}"); } else { ilCallback.seed((Uri) msg.obj); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; network {" + pc.url + "}"); } }; }; executor.execute(new DownloadImageTask(pc, file, mHandler)); } } private void localRequest(String url, final ILCallback ilCallback) { final long start = System.currentTimeMillis(); final PathInfo pc = getLocalPath(url); File file = toFile(pc); if (null != pc.url) { ilCallback.seed(Uri.fromFile(file)); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; cache {" + pc.url + "} "); } } public void localRequest(String url, ImageView iv) { localRequest(url, new ImageViewCallback(iv)); } /** * 请求加载图片* * @param url * @param iv */ public void request(String url, ImageView iv) { request(url, new ImageViewCallback(iv)); } /** * 请求加载图片* * @param url * @param iv */ // public void request(String url, ImageButton iv) { // request(url, new ImageButtonCallbacks(iv)); // } /** * 请求加载图片* * @param url * @param iv */ // public void request(String url, Button iv) { // request(url, new ButtonCallbacks(iv)); // } /** * 请求加载图片* * @param url * @param iv */ public void request(String url, ImageSwitcher iv) { request(url, new ImageSwitcherCallbacks(iv)); } /** * 下载图片任务* * @author Administrator * */ private class DownloadImageTask implements Runnable { private Handler hc; private PathInfo pi; private File file; public DownloadImageTask(PathInfo pi, File file, Handler hc) { this.pi = pi; this.file = file; this.hc = hc; } public void run() { try { byte[] b = requestHttp(pi.url); if (null == b) { throw new IOException("数据为空"); } writeFile(file, b); use.offer(pi); cache.put(pi.url, pi); Message message = new Message(); message.obj = Uri.fromFile(file); hc.sendMessage(message); } catch (IOException e) { Message message = hc.obtainMessage(0, Uri.EMPTY); hc.sendMessage(message); Log.i(TAG, "image download lost.", e); } catch (RuntimeException e) { Message message = hc.obtainMessage(0, Uri.EMPTY); hc.sendMessage(message); Log.i(TAG, "image download lost.", e); } } } private void writeFile(File file, byte[] data) throws IOException { FileOutputStream out = new FileOutputStream(file); try { out.write(data); } finally { out.close(); } } private static byte[] requestHttp(String url) throws IOException { DefaultHttpClient client = new DefaultHttpClient(); System.gc(); try { HttpGet get = new HttpGet(url); HttpResponse res = client.execute(get); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (200 == res.getStatusLine().getStatusCode()) { res.getEntity().writeTo(baos); return baos.toByteArray(); } else { throw new IOException("httpStatusCode:" + res.getStatusLine().getStatusCode()); } } finally { client.getConnectionManager().shutdown(); } } /** * 读取图片路径信息* * @return */ @SuppressWarnings("unchecked") private void loadImagePathInfo() { long start = System.currentTimeMillis(); File file = new File(context.getCacheDir() + "/imagePathCache.json"); try { if (!file.isFile()) { // 文件不存在。 Log.d(TAG, "path info file does not exist"); imageGc(); return; } StringWriter sw = new StringWriter(); char[] buf = new char[1024]; int len; FileReader fr = new FileReader(file); while (-1 != (len = fr.read(buf))) { sw.write(buf, 0, len); } fr.close(); JSONObject json = new JSONObject(sw.toString()); Iterator it = json.keys(); while (it.hasNext()) { String key = it.next(); int id = json.getInt(key); PathInfo pi = new PathInfo(); pi.url = key; pi.id = id; if (index < id) { index = id; } original.add(pi); } // 打开文件文件缓存成功Log.i(TAG, "load path info ok."); } catch (IOException e) { Log.i(TAG, "load path info lost - IOException.", e); imageGc(); } catch (JSONException e) { Log.i(TAG, "load path info lost - JSONException.", e); imageGc(); } finally { if (file.exists()) { file.delete(); Log.d(TAG, "delete path info file"); } Log.d(TAG, "load path info time {" + (System.currentTimeMillis() - start) + "}"); } } /** * 如果路径信息加载失败,清理图片目录。 */ private void imageGc() { long start = System.currentTimeMillis(); try { File dir; if (sdCardExist) { dir = new File(Environment.getExternalStorageDirectory() + "/t_image/"); } else { dir = new File(context.getCacheDir() + "/t_image/"); } if (dir.isDirectory()) { for (File file : dir.listFiles()) { file.delete(); // gc Log.d(TAG_REF, "gc {" + file + "}"); } } } finally { // gc 计时Log.d(TAG_REF, "gc time {" + (System.currentTimeMillis() - start) + "}"); } } private void newImagePathInfo(int max_size) { for (int i = original.size(); i < max_size; i++) { PathInfo pc = new PathInfo(); pc.id = index++; original.add(pc); } } /** * 保存图片路径信息(如记录,下次程序打开,可读取该记录已存图片继续可用) */ public void saveImagePathInfo() { long start = System.currentTimeMillis(); try { JSONObject json = new JSONObject(); for (PathInfo pi : use) { try { json.put(pi.url, pi.id); } catch (JSONException e) { e.printStackTrace(); } } File file = new File(context.getCacheDir() + "/imagePathCache.json"); try { FileWriter fw = new FileWriter(file); fw.write(json.toString()); fw.close(); Log.i(TAG, "image file info save ok."); } catch (IOException e) { e.printStackTrace(); Log.i(TAG, "image file info save lost."); file.delete(); } } finally { Log.d(TAG, "save time {" + (System.currentTimeMillis() - start) + "}"); } } /** * 图片加载回调* * @author n.zhang * */ public static interface ILCallback { public void seed(Uri uri); } private class ImageViewCallback implements ILCallback { public ImageViewCallback(ImageView iv) { if (defaultImageID > 0) { iv.setImageResource(defaultImageID); } this.iv = iv; } private ImageView iv; public void seed(Uri uri) { File f = new File(uri.getPath()); iv.setImageURI(Uri.parse(f.toString())); f = null; } } // private class ImageButtonCallbacks implements ILCallback { // public ImageButtonCallbacks(ImageButton iv) { // if (defaultImageID > 0) { // iv.setBackgroundResource(defaultImageID); ////iv.setImageResource(defaultImageID); // } // this.iv = iv; // } // // private ImageButton iv; // // public void seed(Uri uri) { // iv.setImageURI(uri); // } // } // private class ButtonCallbacks implements ILCallback { // public ButtonCallbacks(Button iv) { // if (defaultImageID > 0) { // iv.setBackgroundResource(defaultImageID); ////iv.setImageResource(defaultImageID); // } // this.iv = iv; // } // // private Button iv; // // public void seed(Uri uri) { // iv.setImageURI(uri); // } // } private class ImageSwitcherCallbacks implements ILCallback { public ImageSwitcherCallbacks(ImageSwitcher iv) { if (defaultImageID > 0) { iv.setImageResource(defaultImageID); } this.iv = iv; } private ImageSwitcher iv; public void seed(Uri uri) { iv.setImageURI(uri); } } } 

看起来问题实际上并不在您发布的代码中。 由于某种原因,流input已关闭。 所以你可能正在关闭image.getPhoto()的流