Miglior modo per determinare se * .doc file è RTF con Java o ColdFusion
-
16-09-2019 - |
Domanda
Così ho circa 4.000 documenti di parola che sto tentando di estrarre il testo da e inserire in una tabella db. Questo funziona swimmingly finché il processore rileva un documento con estensione *.doc
ma determina il file è effettivamente un RTF. Ora so POI non supporta RTFs che va bene, ma ho bisogno di un modo per determinare se un file è in realtà un *.doc
RTF in modo che possa scegliere di ignorare il file e continuare l'elaborazione.
Ho provato diverse tecniche per superare questo, anche utilizzando MimeTypeUtils di ColdFusion, tuttavia, sembra fondare la sua assunzione del tipo MIME sulla estensione del file e ancora classifica il RTF come application / pdf. C'è un altro modo per determinare se un *.doc
è un RTF? Qualsiasi aiuto sarebbe enormemente apprezzato.
Soluzione
Con CF8 e compatibili:
<cffunction name="IsRtfFile" returntype="Boolean" output="false">
<cfargument name="FileName" type="String" />
<cfreturn Left(FileRead(Arguments.FileName),5) EQ '{\rtf' />
</cffunction>
Per le versioni precedenti:
<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>
Aggiornamento: Una risposta migliore CF8 / compatibili. Per evitare di caricare l'intero file in memoria, è possibile effettuare le seguenti operazioni per caricare solo i primi caratteri:
<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>
Sulla base delle osservazioni:
Ecco un modo molto veloce di come si potrebbe fare una generare "quale formato è questo" tipo di funzione. Non perfetto, ma ti dà l'idea ...
<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>
Naturalmente, la pena sottolineare che tutto questo non funzionerà sui formati 'senza intestazione', tra cui molti quelli comuni text-based (CFM, CSS, JS, etc).
Altri suggerimenti
I primi cinque byte di qualsiasi file RTF dovrebbero essere:
{\rtf
Se non lo sono, non è un file RTF.
La sezione dei link esterni nel collegamento articolo Wikipeida alle specifiche per le varie versioni di RTF .
file doc (almeno quelli dal Word '97) usa qualcosa chiamato "Windows Compound formato binario", documentata in formato PDF qui . Secondo tale, questi file doc iniziano con la seguente sequenza:
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
O nel file beta anziani:
0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0
Secondo l'articolo di Wikipedia sulla Parola, ci sono stati almeno 5 diversi formati prima del '97.
In cerca di {\ rtf dovrebbe essere la soluzione migliore.
Buona fortuna, spero che questo aiuta.
È possibile convertire il ByteArray in una stringa
<cfset str = createObject("java", "java.lang.String").init(bytes)>
Si potrebbe anche provare i metodi hasxxxHeader da fonte di POI. Essi determinano se un file di input è qualcosa di POI in grado di gestire: OLE o OOXML. Ma io credo che qualcun altro ha suggerito di utilizzare un semplice try / catch per ignorare i file problematici. C'è una ragione per cui non si desidera farlo? Sembrerebbe l'opzione più semplice.
Aggiornamento: suggerimento di Peter di utilizzare la funzione di CF 8 potrebbe anche funzionare
<cfset input = FileOpen(pathToYourFile)>
<cfset bytes = FileRead(input , 8)>
<cfdump var="#bytes#">
<cfset FileClose(input)>
Si potrebbe provare a identificare i file con la Droid strumento (Record Digital Object Identification), che fornisce l'accesso ai pronom registro tecnico .