【问题标题】:Inputstream handled by different objects depending on the content根据内容由不同对象处理的输入流
【发布时间】:2011-10-10 02:56:23
【问题描述】:

我正在编写一个爬虫/解析器,它应该能够处理不同类型的内容,包括 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)基于 Jsoup 上的 Html 解析器 SAXParser。

【问题讨论】:

    标签: java content-type inputstream


    【解决方案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
    

    【讨论】:

    • 不,我也试过这个方法,不幸的是这个方法不起作用。我不断收到 IOException(“流关闭”)
    • @jerraes:你从哪里得到异常?您的 ContentTypeParser 是否正在关闭流?请在问题中附上您尝试过的问题的详细信息
    • 不,ContentTypeParser 不会关闭流——流只会在 ParserFactory 中的“createParser()”方法结束时关闭。我之前的评论有点太仓促了。当我放置标记时,出现以下错误: java.io.IOException: Resetting to invalid mark at java.io.BufferedInputStream.reset(BufferedInputStream.java:416) at dataAcquisition.Parser.ParseFactory.createParser(ParseFactory.java:65 ) 在 run.Main.main(Main.java:45) 线程“main”中的异常 java.lang.NullPointerException 在 run.Main.main(Main.java:46)
    • @jerraes:这表明您没有将标记限制设置得足够高 - ContentTypeParser 可能正在读取超过 2K 的流。
    • @jerraes:不知道你为什么又发表了同样的评论——基本上我怀疑你没有为mark 电话提供足够高的论据。
    【解决方案2】:

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

    【讨论】:

    • 你的意思是用字符串兑现?也想到了这一点,但我的意思是我必须将此 String 转换回 InputStream 才能使其与 SAXParser 一起使用。如果我不能让它工作,我想这仍然是最好的选择。
    • String 转换为InputStream 非常简单:InputStream is = new ByteArrayInputStream(str.getBytes("UTF-8")); 但是,请参阅 Jon 的 cmets 关于 mark 限制太低:除了过去,没有其他理由会获得无效标记失效限制:download.oracle.com/javase/6/docs/api/java/io/…
    猜你喜欢
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 2016-01-16
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多