2009-04-26 3 views
4

그래서 약 4,000 단어의 문서를 사용하여 텍스트를 추출하고 db 테이블에 삽입하려고합니다. 프로세서가 *.doc 파일 확장자를 가진 문서를 발견하지만 파일이 실제로 RTF 인 것으로 판단 할 때까지 원활하게 작동합니다. POI가 RTF를 지원하지 않는다는 것을 알았지 만, 파일을 무시하고 처리를 계속할 수 있도록 *.doc 파일이 실제로 RTF인지 확인하는 방법이 필요합니다.* .doc 파일이 Java 또는 ColdFusion과 RTF인지 확인하는 가장 좋은 방법

ColdFusion의 MimeTypeUtils를 사용하는 것을 포함하여이를 극복하기위한 몇 가지 방법을 시도했지만, 파일 확장자에 mimetype을 가정하고 여전히 RTF를 application/msword로 분류합니다. *.doc이 RTF인지 확인하는 다른 방법이 있습니까? 어떤 도움이라도 대단히 감사 할 것입니다. 어떤 RTF 파일에

답변

5

:

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


이전 버전 : 더 나은 CF8/호환 답 :

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


업데이트

. 의견을 바탕으로

<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 등)를 포함하여 '헤더가'형식에 모든 작동이 실 거예요.

+0

이것은 완벽합니다! 호기심에서이 기술을 사용하여 문서를 만든 Word의 버전을 검색 할 수 있습니까? POI가 Word 95에서 생성 된 것으로 생각되는 파일에 적합하지 않은 다른 문제를 실행했습니다. 또는 POI를 모두 무시하고 FileRead()로 가져온 데이터를로드하여 db에로드합니다. 방법? 결국 내 목적은 문서의 검색 만 가능하지만 표시 할 수 없게하는 것입니다. –

+0

다른 버전의 파일 표시 자 시퀀스를 식별 할 수있는 경우이 방법을 여러 형식에 사용할 수 있습니다. 많은 바이너리 파일 형식은이 방법으로 형식을 식별하는 최대 8 바이트로 시작하기 때문에이 형식을 사용할 수 있습니다. –

+0

전체 파일을 읽는 경우 ... FileRead를 사용하면 파일을 텍스트로 처리하므로 Word 문서가 손상 될 수 있는지 여부는 알 수 없습니다. 그렇다면 FileReadBinary를 시도해 볼 수는 있지만 데이터베이스의 텍스트로 검색 할 수 있는지 확실하지 않습니다. –

7

처음 다섯 바이트해야한다 : 그렇지 않은 경우

{\rtf 

, 그것이 RTF 파일이 아닙니다.

Wikipeida article의 외부 링크 섹션은 다양한 버전의 RTF에 대한 사양 링크입니다.

Word 파일 (적어도 Word 97 이후)은 in a PDF here으로 문서화 된 "Windows Compound Binary Format"을 사용합니다. 그에 따르면, 이러한 문서 파일은 다음과 같은 순서로 시작 :

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

또는 이전 베타 파일 :

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

을 말씀에 위키 백과 문서에 따르면, 적어도 5 가지 형식 이전에 있었다 '97.

{\ rtf는 최선의 방법입니다.

행운을 빌어, 이것이 도움이되기를 바랍니다.

+0

내가 눈치 않았다 작동합니다. 내가 coldfusion 측면에서 동일한 일을 시도하고 성공적으로 byteArray를 얻을 수 있었지만, 바이트 배열을 바이트로 변환하는 방법을 알아 내려고 노력했다. CF에서 읽을 수있는 문자열로 변환하여 {\ rtf. 대신 내가 얻을 수있는 것은 숫자뿐입니다. 어떤 아이디어? –

+0

표준 FileRead 만 할 수 있습니까? –

0

Pronom technical registry에 액세스 할 수있는 Droid 도구 (디지털 레코드 개체 식별)를 사용하여 파일을 식별해볼 수 있습니다. CF8 및 호환으로

1

당신은 또한 POI의 소스에서 hasxxxHeader 방법을 시도 할 수있는 문자열

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

에 BYTEARRAY을 변환 할 수 있습니다. 그들은 입력 파일이 POI가 처리 할 수있는 것 (OLE 또는 OOXML)인지 결정합니다. 하지만 다른 사람이 간단한 try/catch를 사용하여 문제 파일을 건너 뛰라고 제안했다고 생각합니다. 당신이 그렇게하고 싶지 않은 이유가 있습니까? 그것은 더 단순한 옵션으로 보일 것입니다.

업데이트 : CF 8의 기능을 사용 피터의 제안도 PushbackInputStream는 첫 6 바이트의 BYTEARRAY를 가져옵니다 그 인스턴스화 POI 코드의 일부

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

아, 루프 방법보다 좋습니다. 아마 거기에 명시적인 FileClose (입력)도 있어야할까요? –

+0

예, 명시 적으로 FileClose (..)가 있어야합니다. 나는 그 라인을 복사하는 것을 잊었다. –

관련 문제