当前位置: 首页 > 面试题库 >

如何在Java中读取或解析MHTML(.mht)文件

邓声
2023-03-14
问题内容

我需要挖掘大多数已知文档文件的 内容 ,例如:

  1. pdf格式
  2. html
  3. doc / docx等

对于大多数这些文件格式,我计划使用:

http://tika.apache.org/

但截至目前,Tika它不支持MHTML(*
.mht)文件。(http://en.wikipedia.org/wiki/MHTML)C#中的示例很少(http://www.codeproject.com/KB/
files /
MhtBuilder.aspx
),但在Java中找不到任何文件。

我试图在7Zip中打开*
.mht文件,但失败了…尽管WinZip能够将文件解压缩为图像和文本(CSS,HTML,Script),作为文本和二进制文件…

根据MSDN页面(http://msdn.microsoft.com/zh-
cn/library/aa767785%28VS.85%29.aspx#compress_content)和code project我之前提到的页面… mht文件使用GZip压缩… 。

尝试在Java中解压缩会导致以下异常:With java.uti.zip.GZIPInputStream

java.io.IOException: Not in GZIP format
at java.util.zip.GZIPInputStream.readHeader(Unknown Source)
at java.util.zip.GZIPInputStream.<init>(Unknown Source)
at java.util.zip.GZIPInputStream.<init>(Unknown Source)
at GZipTest.main(GZipTest.java:16)

java.util.zip.ZipFile

 java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
at GZipTest.main(GZipTest.java:21)

请提出如何解压缩它。

谢谢....


问题答案:

坦白说,我没想到会在不久的将来找到解决方案,而我打算放弃,但是我在此页面上偶然发现了一些:

http://en.wikipedia.org/wiki/MIME#Multipart_messages

http://msdn.microsoft.com/zh-
cn/library/ms527355%28EXCHG.10%29.aspx

虽然,乍一看不是很吸引人。但是,如果仔细看,您会得到线索。阅读此内容后,我启动了IE,并随机开始将页面另存为*.mht文件。让我逐行走…

但是让我事先解释一下,我的最终目标是分离/提取html内容并解析它…解决方案本身并不完整,因为它取决于保存时选择的character setencoding。但是即使它会以较小的麻烦提取单个文件…

我希望这对于任何试图解析/解压缩*.mht/MHTML文件的人都是有用的:)

=======说明======== 来自mht文件

From: "Saved by Windows Internet Explorer 7"

它是用于保存文件的软件

Subject: Google
Date: Tue, 13 Jul 2010 21:23:03 +0530
MIME-Version: 1.0

主题,日期和哑剧版本……类似于邮件格式

  Content-Type: multipart/related;
type="text/html";

这部分告诉我们这是一个multipart文档。包含多部分的文档将一个或多个不同的数据集组合在一个正文中,因此multipartContent-
Type字段必须出现在实体的标题中。在这里,我们还可以看到类型为"text/html"

boundary="----=_NextPart_000_0007_01CB22D1.93BBD1A0"

这是最重要的部分。这是唯一的分隔符,它分为两个不同的部分(html,图像,css,脚本等)。 一旦
掌握了这一点,一切都变得很容易…现在,我只需要遍历文档并找出不同的部分,并根据它们的内容Content-Transfer- Encoding(base64,quoted-printable等)保存它们。。。

样品

 ------=_NextPart_000_0007_01CB22D1.93BBD1A0
 Content-Type: text/html;
 charset="utf-8"
 Content-Transfer-Encoding: quoted-printable
 Content-Location: http://www.google.com/webhp?sourceid=navclient&ie=UTF-8

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" =
.
.
.

JAVA代码

用于定义常量的接口。

public interface IConstants 
{
    public String BOUNDARY = "boundary";
    public String CHAR_SET = "charset";
    public String CONTENT_TYPE = "Content-Type";
    public String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
    public String CONTENT_LOCATION = "Content-Location";

    public String UTF8_BOM = "=EF=BB=BF";

    public String UTF16_BOM1 = "=FF=FE";
    public String UTF16_BOM2 = "=FE=FF";
}

主解析器类…

/**
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package com.test.mht.core;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import sun.misc.BASE64Decoder;

/**
 * File to parse and decompose *.mts file in its constituting parts.
 * @author Manish Shukla 
 */

public class MHTParser implements IConstants
{
    private File mhtFile;
    private File outputFolder;

    public MHTParser(File mhtFile, File outputFolder) {
        this.mhtFile = mhtFile;
        this.outputFolder = outputFolder;
    }

    /**
     * @throws Exception
     */
    public void decompress() throws Exception
    {
        BufferedReader reader = null;

        String type = "";
        String encoding = "";
        String location = "";
        String filename = "";
        String charset = "utf-8";
        StringBuilder buffer = null;

        try
        {
            reader = new BufferedReader(new FileReader(mhtFile));

            final String boundary = getBoundary(reader);
            if(boundary == null)
                throw new Exception("Failed to find document 'boundary'... Aborting");

            String line = null;
            int i = 1;
            while((line = reader.readLine()) != null)
            {
                String temp = line.trim();
                if(temp.contains(boundary)) 
                {
                    if(buffer != null) {
                        writeBufferContentToFile(buffer,encoding,filename,charset);
                        buffer = null;
                    }

                    buffer = new StringBuilder();
                }else if(temp.startsWith(CONTENT_TYPE)) {
                    type = getType(temp);
                }else if(temp.startsWith(CHAR_SET)) {
                    charset = getCharSet(temp);
                }else if(temp.startsWith(CONTENT_TRANSFER_ENCODING)) {
                    encoding = getEncoding(temp);
                }else if(temp.startsWith(CONTENT_LOCATION)) {
                    location = temp.substring(temp.indexOf(":")+1).trim();
                    i++;
                    filename = getFileName(location,type);
                }else {
                    if(buffer != null) {
                        buffer.append(line + "\n");
                    }
                }
            }

        }finally 
        {
            if(null != reader)
                reader.close();
        }

    }

    private String getCharSet(String temp) 
    {
        String t = temp.split("=")[1].trim();
        return t.substring(1, t.length()-1);
    }

    /**
     * Save the file as per character set and encoding 
     */
    private void writeBufferContentToFile(StringBuilder buffer,String encoding, String filename, String charset) 
    throws Exception
    {

        if(!outputFolder.exists())
            outputFolder.mkdirs();

        byte[] content = null;

        boolean text = true;

        if(encoding.equalsIgnoreCase("base64")){
            content = getBase64EncodedString(buffer);
            text = false;
        }else if(encoding.equalsIgnoreCase("quoted-printable")) {
            content = getQuotedPrintableString(buffer);         
        }
        else
            content = buffer.toString().getBytes();

        if(!text)
        {
            BufferedOutputStream bos = null;
            try
            {
                bos = new BufferedOutputStream(new FileOutputStream(filename));
                bos.write(content);
                bos.flush();
            }finally {
                bos.close();
            }
        }else 
        {
            BufferedWriter bw = null;
            try
            {
                bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), charset));
                bw.write(new String(content));
                bw.flush();
            }finally {
                bw.close();
            }
        }
    }

    /**
     * When the save the *.mts file with 'utf-8' encoding then it appends '=EF=BB=BF'</br>
     * @see http://en.wikipedia.org/wiki/Byte_order_mark
     */
    private byte[] getQuotedPrintableString(StringBuilder buffer) 
    {
        //Set<String> uniqueHex = new HashSet<String>();
        //final Pattern p = Pattern.compile("(=\\p{XDigit}{2})*");

        String temp = buffer.toString().replaceAll(UTF8_BOM, "").replaceAll("=\n", "");

        //Matcher m = p.matcher(temp);
        //while(m.find()) {
        //  uniqueHex.add(m.group());
        //}

        //System.out.println(uniqueHex);

        //for (String hex : uniqueHex) {
            //temp = temp.replaceAll(hex, getASCIIValue(hex.substring(1)));
        //}

        return temp.getBytes();
    }

    /*private String getASCIIValue(String hex) {
        return ""+(char)Integer.parseInt(hex, 16);
    }*/
    /**
     * Although system dependent..it works well
     */
    private byte[] getBase64EncodedString(StringBuilder buffer) throws Exception {
        return new BASE64Decoder().decodeBuffer(buffer.toString());
    }

    /**
     * Tries to get a qualified file name. If the name is not apparent it tries to guess it from the URL.
     * Otherwise it returns 'unknown.<type>'
     */
    private String getFileName(String location, String type) 
    {
        final Pattern p = Pattern.compile("(\\w|_|-)+\\.\\w+");
        String ext = "";
        String name = "";
        if(type.toLowerCase().endsWith("jpeg"))
            ext = "jpg";
        else
            ext = type.split("/")[1];

        if(location.endsWith("/")) {
            name = "main";
        }else
        {
            name = location.substring(location.lastIndexOf("/") + 1);

            Matcher m = p.matcher(name);
            String fname = "";
            while(m.find()) {
                fname = m.group();
            }

            if(fname.trim().length() == 0)
                name = "unknown";
            else
                return getUniqueName(fname.substring(0,fname.indexOf(".")), fname.substring(fname.indexOf(".") + 1, fname.length()));
        }
        return getUniqueName(name,ext);
    }

    /**
     * Returns a qualified unique output file path for the parsed path.</br>
     * In case the file already exist it appends a numarical value a continues
     */
    private String getUniqueName(String name,String ext)
    {
        int i = 1;
        File file = new File(outputFolder,name + "." + ext);
        if(file.exists())
        {
            while(true)
            {
                file = new File(outputFolder, name + i + "." + ext);
                if(!file.exists())
                    return file.getAbsolutePath();
                i++;
            }
        }

        return file.getAbsolutePath();
    }

    private String getType(String line) {
        return splitUsingColonSpace(line);
    }

    private String getEncoding(String line){
        return splitUsingColonSpace(line);
    }

    private String splitUsingColonSpace(String line) {
        return line.split(":\\s*")[1].replaceAll(";", "");
    }

    /**
     * Gives you the boundary string
     */
    private String getBoundary(BufferedReader reader) throws Exception 
    {
        String line = null;

        while((line = reader.readLine()) != null)
        {
            line = line.trim();
            if(line.startsWith(BOUNDARY)) {
                return line.substring(line.indexOf("\"") + 1, line.lastIndexOf("\""));
            }
        }

        return null;
    }
}

问候,



 类似资料:
  • 本文向大家介绍java如何解析/读取xml文件,包括了java如何解析/读取xml文件的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java解析/读取xml文件的方法,供大家参考,具体内容如下 XML文件 Java 代码: 以上就是本文的全部内容,希望对大家的学习有所帮助。

  • 问题内容: 我想使用scala解析.mht文件,但是我发现我的代码与Java完全一样。 以下是文件样本: 有一个名为的特殊行,它是分隔符行: 第一部分是有关此文件的一些信息,可以忽略。以下是4个块,第一个是文件,其他是带有编码文本的图像。 如果我使用Java,则代码如下: 我尝试使用scala重写代码,但是我发现我的代码结构几乎相同,只是我使用了scala语法而不是Java。 是否有scala方法

  • 如何在java StaX解析器中读取此xml。这是示例 xml。原始文件大小大于 2 GB。所以只有我去StaX解析器。我的Java类是BulkFileReader.java 我使用此java代码从xml标记中检索值。当我使用这个代码时。我可以检索第三个

  • 我试图理解STAX java的机制是如何工作的。 我有这个xml文件 为了模仿这个XML文件的行为,我们创建了一个具有相似属性的对象 有了这个,我尝试读取我的xml文件: 我的问题是,它们是5个产品,但当我试图输出它们时,它们不是正确的数字。1.If in:If(startElement.getName().getLocalPart()。equals(“orders”))最后一个参数是“oders

  • 问题内容: 我有一个C-Header文件,定义了几个构造,包含多个char数组。 我想使用Java解析这些文件。是否存在用于将C-Header文件读入结构的库,或者是否存在可以理解C-Header文件的流解析器? 只是为了获得更多背景信息(我只是在寻找C-Header解析器,而不是针对此特定问题的解决方案):我有一个包含数据的文本文件和一个解释结构的C- Header文件。两者都有点动态,所以我不

  • 问题内容: 呼吁专家,专家和其他人来帮助阅读和解析python文件。 在第六版的第751页。或第7版第800页。Superbible OpenGL的附录B。SBM文件格式似乎在某种程度上很好地解释了该格式。 我试图在python中实现此文件格式的阅读器。 好的,已经取得了进展。我已经将Rabbid76惊人的代码合并到提供的源代码中。尽管我正在尝试取得更多进展。 更新2019年6月23日-重大进展,