4

所以我有大约 4,000 个单词的文档,我试图从中提取文本并插入到一个 db 表中。这在处理器遇到具有*.doc文件扩展名的文档但确定该文件实际上是 RTF 之前一直有效。现在我知道 POI 不支持 RTF,这很好,但我确实需要一种方法来确定*.doc文件是否实际上是 RTF,以便我可以选择忽略文件并继续处理。

我尝试了几种技术来克服这个问题,包括使用 ColdFusion 的 MimeTypeUtils,但是,它似乎基于文件扩展名对 mimetype 的假设,并且仍然将 RTF 分类为 application/msword。有没有其他方法可以确定 a*.doc是否是 RTF?任何帮助将不胜感激。

4

4 回答 4

7

任何 RTF 文件中的前五个字节应该是:

{\rtf

如果不是,则它不是 RTF 文件。

Wikipeida 文章中的外部链接部分链接到各种 RTF 版本的规范。

Doc 文件(至少是自 Word '97 以来的文件)使用一种称为“Windows 复合二进制格式”的文件,在此处以 PDF格式记录。据此,这些 Doc 文件以以下顺序开始:

0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1

或者在旧的 beta 文件中:

0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0

根据维基百科关于 Word 的文章,在 97 年之前至少有 5 种不同的格式。

寻找 {\rtf 应该是你最好的选择。

祝你好运,希望这会有帮助。

于 2009-04-26T00:45:03.760 回答
5

带CF8并兼容:

<cffunction name="IsRtfFile" returntype="Boolean" output="false">
    <cfargument name="FileName" type="String" />
    <cfreturn Left(FileRead(Arguments.FileName),5) EQ '{\rtf' />
</cffunction>


对于早期版本:

<cffunction name="IsRtfFile" returntype="Boolean" output="false">
    <cfargument name="FileName" type="String" />
    <cfset var FileData = 0 />
    <cffile variable="FileData" action="read" file="#Arguments.FileName#" />
    <cfreturn Left(FileData,5) EQ '{\rtf' />
</cffunction>


更新:更好的 CF8/兼容答案。为避免将整个文件加载到内存中,您可以执行以下操作以仅加载前几个字符:

<cffunction name="IsRtfFile" returntype="Boolean" output="false">
    <cfargument name="FileName" type="String" />
    <cfset var FileData = 0 />

    <cfloop index="FileData" file="#Arguments.FileName#" characters="5">
        <cfbreak/>
    </cfloop>

    <cfreturn FileData EQ '{\rtf' />
</cffunction>


根据评论:
这是一种非常快速的方法,您可以生成“这是什么格式”类型的函数。不完美,但它给你的想法......

<cffunction name="determineFileFormat" returntype="String" output="false"
    hint="Determines format of file based on header of the file's data."
    >
    <cfargument name="FileName" type="String"/>
    <cfset var FileData = 0 />
    <cfset var CurFormat = 0 />
    <cfset var MaxBytes = 8 />
    <cfset var Formats =
        { WordNew  : 'D0,CF,11,E0,A1,B1,1A,E1'
        , WordBeta : '0E,11,FC,0D,D0,CF,11,E0'
        , Rtf      : '7B,5C,72,74,66' <!--- {\rtf --->
        , Jpeg     : 'FF,D8'
        }/>

    <cfloop index="FileData" file="#Arguments.FileName#" characters="#MaxBytes#">
        <cfbreak/>
    </cfloop>

    <cfloop item="CurFormat" collection="#Formats#">
        <cfif Left( FileData , ListLen(Formats[CurFormat]) ) EQ convertToText(Formats[CurFormat]) >
            <cfreturn CurFormat />
        </cfif>
    </cfloop>

    <cfreturn "Unknown"/>
</cffunction>


<cffunction name="convertToText" returntype="String" output="false">
    <cfargument name="HexList" type="String" />
    <cfset var Result = "" />
    <cfset var CurItem = 0 />

    <cfloop index="CurItem" list="#Arguments.HexList#">
        <cfset Result &= Chr(InputBaseN(CurItem,16)) />
    </cfloop>

    <cfreturn Result />
</cffunction>

当然,值得指出的是,所有这些都不适用于“无标题”格式,包括许多常见的基于文本的格式(CFM、CSS、JS 等)。

于 2009-04-26T02:53:49.473 回答
1

您可以将 byteArray 转换为字符串

<cfset str = createObject("java", "java.lang.String").init(bytes)>

您也可以尝试 POI 源中的 hasxxxHeader 方法。它们确定输入文件是否是 POI 可以处理的:OLE 或 OOXML。但我相信其他人建议使用简单的 try/catch 来跳过问题文件。您是否有理由不希望这样做?这似乎是更简单的选择。

更新: 彼得建议使用 CF 8 的功能也可以

<cfset input = FileOpen(pathToYourFile)>
<cfset bytes = FileRead(input , 8)>
<cfdump var="#bytes#">
<cfset FileClose(input)>
于 2009-04-27T16:31:47.390 回答
0

您可以尝试使用Droid工具(数字记录对象识别)识别文件,该工具提供对Pronom 技术注册表的访问。

于 2009-04-26T01:35:28.147 回答