所以我有大约4,000个word文档,我试图从中提取文本并插入到db表中。这可以顺利运行,直到处理器遇到具有*.doc
文件扩展名的文档,但确定该文件实际上是RTF。现在我知道POI不支持RTF,但是我确实需要一种方法来确定*.doc
文件是否实际上是RTF,以便我可以选择忽略该文件并继续处理。
我已经尝试了几种技术来克服这个问题,包括使用ColdFusion的MimeTypeUtils,但是,它似乎基于文件扩展名的mimetype假设,并仍然将RTF分类为application / msword。有没有其他方法可以确定*.doc
是否是RTF?任何帮助都将非常感激。
答案 0 :(得分:7)
任何RTF文件中的前五个字节应为:
{\rtf
如果不是,则不是RTF文件。
Wikipeida article中的外部链接部分链接到各种版本的RTF的规范。
Doc文件(至少自Word '97以来的文件)使用称为“Windows复合二进制格式”的文件,记录为in a PDF here。据此,这些Doc文件以以下顺序开头:
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
或旧的测试版文件:
0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0
根据维基百科关于Word的文章,在'97之前至少有5种不同的格式。
寻找{\ rtf应该是你最好的选择。
祝你好运,希望这会有所帮助。答案 1 :(得分: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等)。
答案 2 :(得分:1)
您可以将byteArray转换为字符串
<cfset str = createObject("java", "java.lang.String").init(bytes)>
您也可以尝试POI源代码中的hasxxxHeader方法。它们确定输入文件是否是POI可以处理的内容:OLE或OOXML。但我相信其他人建议使用简单的try / catch来跳过问题文件。你有什么理由不这样做吗?这似乎是更简单的选择。
<强>更新强> Peter建议使用CF 8的功能也可以使用
<cfset input = FileOpen(pathToYourFile)>
<cfset bytes = FileRead(input , 8)>
<cfdump var="#bytes#">
<cfset FileClose(input)>
答案 3 :(得分:0)
您可以尝试使用Droid工具(数字记录对象标识)识别文件,该工具可以访问Pronom technical registry。