将SelfExpandingBufferredInputStream转换为XSSFWorkbook时遭遇UnsupportedOperationException问题求助
解决SelfExpandingBufferredInputStream转XSSFWorkbook的UnsupportedOperationException问题
这个错误的根源很明确:SelfExpandingBufferredInputStream(注:类名拼写里的Bufferred少了一个f)重写了mark()方法并强制抛出异常,因为它的设计逻辑是始终标记在索引0的位置,不支持自定义标记和重置操作。而POI的XSSFWorkbook在解析Excel文件时,会尝试调用流的mark()和reset()来校验文件格式、处理文件头等逻辑,两者的行为冲突直接触发了报错。
下面给你两种可行的解决方案,按需选择:
方案一:用BufferedInputStream包装原流(内存友好,推荐)
BufferedInputStream是Java自带的流包装类,会把输入流的数据缓存到内存中,天然支持mark()和reset()操作,完美适配POI的需求:
final Response httpResponse = webTarget.path(REQUEST_PATH) .resolveTemplate("docId", docId) .request("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") .header(RequestInvokerConstants.ACCEPT_TYPE, MediaType.WILDCARD) .header("context", context) .get(); InputStream inputStream = httpResponse.readEntity(InputStream.class); // 用BufferedInputStream包装原流,解决mark/reset不支持的问题 try (BufferedInputStream bufferedStream = new BufferedInputStream(inputStream)) { Workbook workbook = new XSSFWorkbook(bufferedStream); // 后续操作workbook... } catch (IOException e) { // 处理IO异常 }
如果你的Excel文件较大,可以手动指定缓冲大小(比如new BufferedInputStream(inputStream, 16384)),平衡内存占用和读取性能。
方案二:将流读取到内存字节数组(适合小文件)
把原流的全部内容读取到字节数组,再用ByteArrayInputStream包装——这个类基于内存数组实现,完全支持mark()和reset():
final Response httpResponse = webTarget.path(REQUEST_PATH) .resolveTemplate("docId", docId) .request("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") .header(RequestInvokerConstants.ACCEPT_TYPE, MediaType.WILDCARD) .header("context", context) .get(); InputStream inputStream = httpResponse.readEntity(InputStream.class); try { // 读取流到字节数组(这里用Apache Commons IO的IOUtils,也可以自己实现) byte[] excelBytes = IOUtils.toByteArray(inputStream); try (ByteArrayInputStream byteArrayStream = new ByteArrayInputStream(excelBytes)) { Workbook workbook = new XSSFWorkbook(byteArrayStream); // 后续操作workbook... } } catch (IOException e) { // 处理IO异常 }
如果不想依赖Apache Commons IO,可以自己实现流转字节数组的工具方法:
private static byte[] readStreamToByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int readLen; while ((readLen = input.read(buffer)) != -1) { output.write(buffer, 0, readLen); } output.flush(); return output.toByteArray(); }
注意:如果处理的是超大Excel文件,方案二可能会导致内存占用过高,这时候优先选方案一。
内容的提问来源于stack exchange,提问作者Sooriya
相关产品推荐
相关产品推荐

