近期工作中, 遇到了有送EOFException的抛出, 以此小节总结学习相关内容, 及如何解决问题。
doUnZip(FileOperateUtil.java:239)] java.io.EOFException
com.tr..base.util.FileOperateUtil.doUnZip(FileOperateUtil.java:221)] java.io.EOFException
at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)
at java.util.zip.GZIPInputStream.readUShort(GZIPInputStream.java:258)
at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
at java.util.zip.GZIPInputStream.(GZIPInputStream.java:79)
at java.util.zip.GZIPInputStream.(GZIPInputStream.java:91)
at com.tr..base.util.FileOperateUtil.doUnZip(FileOperateUtil.java:208)
at com.tr..framework.input.transformation.workflow.FileUncompressProcessor.process(FileUncompressProcessor.java:44)
at com.tr..workflow.Workflow.process(Workflow.java:50)
at com.tr..framework.input.transformation.PollingFileTask.run(PollingFileService.java:100)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
应用程序运行的背景是, 从一个文件服务器上下载文件, 文件类型里面有压缩文件, 下载到本地需要解压缩。 在解压缩的过程中出现了EOFException的异常。
首先查看出问题的代码片段:
// set the input and output stream
InputStream input = null;
GZIPInputStream zipInputStream = null;
OutputStream output = null;
try {
input = new FileInputStream(file);
zipInputStream = new GZIPInputStream(input);
output = new FileOutputStream(unZipFilePath);
byte[] data = new byte[BUFFER];
while ((count = zipInputStream.read(data, 0, BUFFER)) != -1) {
output.write(data, 0, count);
}
output.flush();
success = true;
} catch (FileNotFoundException e) {
success = false;
logger.error(ExceptionUtils.getStackTrace(e));
} catch (IOException e) {
success = false;
logger.error(ExceptionUtils.getStackTrace(e));
} finally {
try {
if (input != null) {
input.close();
}
if (output != null) {
output.flush();
output.close();
}
} catch (IOException e) {
logger.error(ExceptionUtils.getStackTrace(e));
}
}
文件读入缓存后, 通过java.util.zip.GZIPInputStream解压缩,得到GZIPInputStream的输出流。这两个类在rt.jar里, 是Java提供的util API。
接下来查看Java API如何对这个异常及类的解析文件定义的。
1. 分析出问题的这一行源码:
at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)
通过查看Java API的源码这个方法会抛出java.io.IOException:
/*
* Reads unsigned byte.
*/
private int readUByte(InputStream in) throws IOException {
int b = in.read();
if (b == -1) {
throw new EOFException();
}
if (b < -1 || b > 255) {
// Report on this.in, not argument in; see read{Header, Trailer}.
throw new IOException(this.in.getClass().getName()
+ ".read() returned value out of range -1..255: " + b);
}
return b;
}
2. 查看EOFException的类继承结构,如下图:
由此可见EOFException是IOException的子类, 当{b == -1}时会抛出这个异常, 由此可以说明文件在开始读取时直接读到了文件尾结束的标识符, 由此可以推测,文件打包可能被破坏, 或者这是个空包。
经过进一步分析发现文件被下载过程中, 上游程序的漏洞引起创建本地空压缩包引起的异常。当你用判断文件是否存在时, 这个文件是存在的。
// get the file object
File file = new File(filePath);
if (!file.exists()) {
success = false;
return success;
}
因此只能通过判断InputStream是否为空来解决这问题。当input.available() == 0时, 说明文件已经读到末尾。因此,可以断定这是一个空文件。代码如下:
input = new FileInputStream(file);
if(input.available() == 0){
logger.debug("The file "+unZipFilePath+" is empty, ignore it.");
success = false;
}else{
zipInputStream = new GZIPInputStream(input);
output = new FileOutputStream(unZipFilePath);
byte[] data = new byte[BUFFER];
while ((count = zipInputStream.read(data, 0, BUFFER)) != -1) {
output.write(data, 0, count);
}
output.flush();
success = true;
}