Pergunta

Então, eu tenho cerca de 4.000 documentos do Word que eu estou tentando extrair o texto de e inserção em uma tabela db. Isso funciona maravilhas até que o processador encontra um documento com a extensão de arquivo *.doc mas determina o arquivo é na verdade um RTF. Agora eu sei que POI não suporta RTFs que é bom, mas eu preciso de uma maneira de determinar se um arquivo *.doc é realmente um RTF para que eu possa optar por ignorar o arquivo e continuar processando.

Eu tentei várias técnicas para superar este, incluindo o uso MimeTypeUtils do ColdFusion, no entanto, parece basear a sua assunção do mimetype na extensão do arquivo e ainda classifica o RTF como application / msword. Existe alguma outra maneira de determinar se um *.doc é um RTF? Qualquer ajuda seria extremamente apreciado.

Foi útil?

Solução

Com CF8 e compatíveis:

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


Para versões anteriores:

<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>


Update: A melhor CF8 / resposta compatível. Para evitar carregar o arquivo inteiro na memória, você pode fazer o seguinte para carregar apenas os primeiros caracteres:

<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>


Com base nos comentários:
Aqui está uma maneira muito rápida, como você pode fazer a gerar "o formato é esse" tipo de função. Não é perfeito, mas dá-lhe a idéia ...

<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>

É claro, salientar que tudo isto vai funcionar em formatos 'sem cabeçalho', inclusive muitos comuns baseados em texto (CFM, CSS, JS, etc).

Outras dicas

Os primeiros cinco bytes em qualquer arquivo RTF deve ser:

{\rtf

Se não forem, não é um arquivo RTF.

A seção de links externos no Wikipeida link do artigo com as especificações para as várias versões de RTF .

arquivos DOC (pelo menos aqueles desde Palavra '97) o uso de algo chamado "Windows Composto binário Format", documentado em um PDF aqui . De acordo com isso, esses arquivos Doc começar com a seguinte sequência:

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

Ou em arquivos beta mais velhos:

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

De acordo com o artigo da Wikipedia sobre Word, havia pelo menos 5 formatos diferentes antes de '97.

Olhando para {\ rtf deve ser sua melhor aposta.

Boa sorte, espero que isso ajude.

Você pode converter o byteArray para uma string

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

Você também pode tentar os métodos hasxxxHeader de fonte de POI. Eles determinar se um arquivo de entrada é algo POI pode lidar com: OLE ou OOXML. Mas eu acredito que alguém sugeriu usando um simples try / catch para ignorar arquivos de problema. Existe uma razão que você não deseja fazer isso? Parece a opção mais simples.

Update: sugestão de usar a função do CF 8 de Peter também funcionaria

<cfset input = FileOpen(pathToYourFile)>
<cfset bytes = FileRead(input , 8)>
<cfdump var="#bytes#">
<cfset FileClose(input)>

Você poderia tentar identificar os arquivos com a Droid ferramenta (Record Identificação Digital Object), que fornece acesso a pronom técnico registro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top