关于BufferedInputStream类的mark与reset方法的一个bug的问题

BufferedInputStream mark与reset bug
探讨了Java中BufferedInputStream类的mark与reset方法在特定条件下触发的异常问题,并提出了三种解决方案。

关于BufferedInputStream类的mark与reset方法的一个bug的问题.txt
sylilzy@gmail.com 施祖阳 http://www.shizuyang.cn
2010-7-7 13:20:26 星期三

最近在调试程序时发现BufferedInputStream类的mark与reset方法存在一个bug,重现方式如下:

import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class BugTest {
/**
* @param args
*/
static public void main(String[] p) throws Exception {
   BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e://temp//a.txt"));
   int available = bis.available();
   System.out.println("available:" + available);
   // ---
   int markLimit = available;
   bis.mark(markLimit);
   System.out.println("---mark:" + markLimit);
   byte[] temp = new byte[available];
   bis.read(temp);
   System.out.println("---read:" + available);
   System.out.println("---read one byte:" + bis.read());
   bis.reset();
   System.out.println("reset ok!");
   bis.close();
}
}

在以上类运行时,如果e://temp//a.txt文件的大小在8192字节以上,则运行结果如下:
available:8384
---mark:8384
---read:8384
---read one byte:-1
Exception in thread "main" java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(Unknown Source)
at com.BugTest.main(BugTest.java:22)

如果e://temp//a.txt文件的大小在8192字节以下,则不会有此异常。

为了分析问题产生的原因,我写了如下一个类来显示BufferedInputStream类的相关信息:


import java.io.BufferedInputStream;
import java.io.InputStream;

public class MyBuffer extends BufferedInputStream {
public MyBuffer(InputStream in, int size) {
   super(in, size);
   // TODO Auto-generated constructor stub
}

public MyBuffer(InputStream in) {
   super(in);
   // TODO Auto-generated constructor stub
}

public int getMarklimit() {
   return marklimit;
}

public int getMarkPosition() {
   return markpos;
}

public int getBufferLength() {
   return buf.length;
}
}

测试类修改如下:

import java.io.*;
import java.util.regex.Pattern;

/**
* @author shizy TODO To change the template for this generated type comment go
*         to Window - Preferences - Java - Code Style - Code Templates
*/
public class Test {
static public void main(String[] p) throws Exception {
   MyBuffer bis = new MyBuffer(new FileInputStream("e://temp//a.txt"));
   int available = bis.available();
   System.out.println("available:" + available);
   System.out.println("getBufferLength:" + bis.getBufferLength());
   System.out.println("getMarklimit:" + bis.getMarklimit());
   System.out.println("getMarkPosition:" + bis.getMarkPosition());
   // ---
   int markLimit = available;
   bis.mark(markLimit);
   System.out.println("---mark:" + markLimit);
   System.out.println("getBufferLength:" + bis.getBufferLength());
   System.out.println("getMarklimit:" + bis.getMarklimit());
   System.out.println("getMarkPosition:" + bis.getMarkPosition());
   byte[] temp = new byte[available];
   bis.read(temp);
   System.out.println("---read:" + available);
   System.out.println("getBufferLength:" + bis.getBufferLength());
   System.out.println("getMarklimit:" + bis.getMarklimit());
   System.out.println("getMarkPosition:" + bis.getMarkPosition());
   System.out.println("---read one byte:" + bis.read());
   System.out.println("getBufferLength:" + bis.getBufferLength());
   System.out.println("getMarklimit:" + bis.getMarklimit());
   System.out.println("getMarkPosition:" + bis.getMarkPosition());
   bis.reset();
   System.out.println("reset ok!");
   bis.close();
}
}

则运行结果如下:
available:8384
getBufferLength:8192
getMarklimit:0
getMarkPosition:-1
---mark:8384
getBufferLength:8192
getMarklimit:8384
getMarkPosition:0
---read:8384
getBufferLength:8384
getMarklimit:8384
getMarkPosition:0
---read one byte:-1
getBufferLength:8384
getMarklimit:8384
getMarkPosition:-1
Exception in thread "main" java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(Unknown Source)
at com.Test.main(Test.java:41)

可见,在输出了“---read:8384”后,BufferLength变成了与Marklimit一样的大小,但在"---read one byte:-1"后,MarkPosition变成了-1,导致了reset时出错。

解决办法有三种:
1.增加BufferedInputStream的BufferLength,在上例中,增加到8385则可解决问题。但此大小需要由输入流的数据量解定,此方法并不太可行。
2.改变markLimit大小。将int markLimit = available;修改为:int markLimit = available+1;。采用这种方式,则上例运行结果如下:
available:8384
getBufferLength:8192
getMarklimit:0
getMarkPosition:-1
---mark:8385
getBufferLength:8192
getMarklimit:8385
getMarkPosition:0
---read:8384
getBufferLength:8385
getMarklimit:8385
getMarkPosition:0
---read one byte:-1
getBufferLength:8385
getMarklimit:8385
getMarkPosition:0
reset ok!

3.不要在流数据结束之后再调用bis.read方法,这种方法并不能完全保证不出问题,因为流数据是否结束,必须要通过read的返回值才能知道。

看来,此问题的出现情况是当BufferLength刚好与从输入流读入的数据相等时(缓冲区会随着marklimit大小增长),如果再读入数据,即时此时未读入数据,则也会认为超过了Marklimit限制,则reset会抛出异常。

注:
jdk版本:
java version "1.6.0_05"
Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)

package com.zzyl.common.utils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; import java.io.File; import java.io.IOException; import java.io.InputStream; public class PDFUtil { public static String pdfToString(InputStream inputStream) { PDDocument document = null; try { // 加载PDF文档 document = PDDocument.load(inputStream); // 创建一个PDFTextStripper实例来提取文本 PDFTextStripper pdfStripper = new PDFTextStripper(); // 从PDF文档中提取文本 String text = pdfStripper.getText(document); return text; } catch (IOException e) { e.printStackTrace(); } finally { // 关闭PDF文档 if (document != null) { try { document.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } } java.io.EOFException: null at org.apache.fontbox.ttf.TTFDataStream.readUnsignedInt(TTFDataStream.java:151) at org.apache.fontbox.ttf.TTFParser.readTableDirectory(TTFParser.java:312) at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:139) at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:87) at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.addTrueTypeFont(FileSystemFontProvider.java:657) at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.scanFonts(FileSystemFontProvider.java:379) at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.<init>(FileSystemFontProvider.java:358) at org.apache.pdfbox.pdmodel.font.FontMapperImpl$DefaultFontProvider.<clinit>(FontMapperImpl.java:140) at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getProvider(FontMapperImpl.java:159) at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFont(FontMapperImpl.java:423) at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getTrueTypeFont(FontMapperImpl.java:331) at org.apache.pdfbox.pdmodel.font.PDTrueTypeFont.<init>(PDTrueTypeFont.java:215) at org.apache.pdfbox.pdmodel.font.PDFontFactory.createFont(PDFontFactory.java:89) at org.apache.pdfbox.pdmodel.PDResources.getFont(PDResources.java:146) at org.apache.pdfbox.contentstream.operator.text.SetFontAndSize.process(SetFontAndSize.java:66) at org.apache.pdfbox.contentstream.PDFStreamEngine.processOperator(PDFStreamEngine.java:933) at org.apache.pdfbox.contentstream.PDFStreamEngine.processStreamOperators(PDFStreamEngine.java:514) at org.apache.pdfbox.contentstream.PDFStreamEngine.processStream(PDFStreamEngine.java:492) at org.apache.pdfbox.contentstream.PDFStreamEngine.processPage(PDFStreamEngine.java:155) at org.apache.pdfbox.text.LegacyPDFStreamEngine.processPage(LegacyPDFStreamEngine.java:144) at org.apache.pdfbox.text.PDFTextStripper.processPage(PDFTextStripper.java:394) at org.apache.pdfbox.text.PDFTextStripper.processPages(PDFTextStripper.java:322) at org.apache.pdfbox.text.PDFTextStripper.writeText(PDFTextStripper.java:269) at org.apache.pdfbox.text.PDFTextStripper.getText(PDFTextStripper.java:233) at com.zzyl.common.utils.PDFUtil.pdfToString(PDFUtil.java:25) at com.zzyl.nursing.controller.HealthAssessmentController.uploadFile(HealthAssessmentController.java:134)
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值