输入流由不同对象处理,具体取决于内容

时间:2011-07-21 10:35:59

标签: java content-type inputstream

我正在编写一个爬虫/解析器,它应该能够处理不同类型的内容,包括RSS,Atom和普通的html文件。为了确定正确的解析器,我编写了一个名为ParseFactory的类,它接受一个URL,尝试检测内容类型,并返回正确的解析器。

不幸的是,使用URLConnection中提供的in方法检查内容类型并不总是有效。例如,

String contentType = url.openConnection().getContentType();

并不总是提供正确的内容类型(例如“text / html”应该是RSS)或者不允许区分RSS和Atom(例如“application / xml”既可以是Atom,也可以是一个RSS提要)。为了解决这个问题,我开始在InputStream中寻找线索。问题是我遇到了一个优雅的类设计,我需要只下载一次InputStream。在我目前的设计中,我首先编写了一个单独的类来确定正确的内容类型,然后ParseFactory使用这些信息来创建相应解析器的实例,反过来,当调用方法'parse()'时,下载整个InputStream第二次。

public Parser createParser(){

    InputStream inputStream = null;
    String contentType = null;
    String contentEncoding = null;

    ContentTypeParser contentTypeParser = new ContentTypeParser(this.url);
    Parser parser = null;

    try {

        inputStream = new BufferedInputStream(this.url.openStream());
        contentTypeParser.parse(inputStream);
        contentType = contentTypeParser.getContentType();
        contentEncoding = contentTypeParser.getContentEncoding();

        assert (contentType != null);

        inputStream = new BufferedInputStream(this.url.openStream());

        if (contentType.equals(ContentTypes.rss))
        {
            logger.info("RSS feed detected");
            parser = new RssParser(this.url);
            parser.parse(inputStream);
        }
        else if (contentType.equals(ContentTypes.atom))
        {
            logger.info("Atom feed detected");
            parser = new AtomParser(this.url);
        }
        else if (contentType.equals(ContentTypes.html))
        {
            logger.info("html detected");
            parser = new HtmlParser(this.url);
            parser.setContentEncoding(contentEncoding);
        }
        else if (contentType.equals(ContentTypes.UNKNOWN))
            logger.debug("Unable to recognize content type");

        if (parser != null)
            parser.parse(inputStream);

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return parser;

}

基本上,我正在寻找一种解决方案,允许我消除第二个“inputStream = new BufferedInputStream(this.url.openStream())”。

非常感谢任何帮助!

附注1:为了完整起见,我也尝试使用URLConnection.guessContentTypeFromStream(inputStream)方法,但这种方法经常返回null。

附注2:XML解析器(Atom和Rss)基于SAXParser,即Jsoup上的Html解析器。

2 个答案:

答案 0 :(得分:1)

您可以致电markreset吗?

inputStream = new BufferedInputStream(this.url.openStream());
inputStream.mark(2048); // Or some other sensible number

contentTypeParser.parse(inputStream);
contentType = contentTypeParser.getContentType();
contentEncoding = contentTypeParser.getContentEncoding();

inputstream.reset(); // Let the parser have a crack at it now

答案 1 :(得分:0)

也许您的ContentTypeParser应该在内部缓存内容并将其提供给相应的ContentParser,而不是从InputStream获取数据。