2015-01-22 5 views
1

FAR 및 WIDE에 대한 정확한 검색 결과가 있지만 아무것도 찾을 수 없습니다. UTL_FILE 스크립트를 사용하여 Oracle 테이블에서 일부 파일 BLOB를 풀어 파일 디렉토리에 저장합니다. 그것은 많은 파일을 위해 일하고 있지만 제거 과정을 통해 "틀에 얽매이지 않는"파일 이름을 가진 파일에 문제가 있다는 것을 좁혀 냈습니다. 그래도 유효한 파일 임에도 불구하고 파일이 전송 중에 손상되었습니다. 원래는 30kb 밖에 없었지만 5kb로 내보낼 수는 없습니다. 그래서 나는 그것이 큰 파일 크기 문제가 아니라는 것을 안다. 파일은 응용 프로그램을 통해 정상적으로 열리고 유효한 MIME 유형 인코딩이 있으며 그렇지 않으면 파일 시스템에서 정상적으로 열리지 만 UTL_FILE은 해당 파일을 좋아하지 않습니다. 그들은 여분의 "."파일이 있습니다. 예 : john.smith.doc 또는 파운드 기호 즉 : Smith # 12345.doc 또는 괄호 등. Oracle 테이블에서 소스 파일 이름을 변경할 수는 없지만 ID 번호를 연결할 때 그들을 저장하기 때문에 나중에 SQL 파일 테이블에 ETL로드를위한 키로 참조 할 수 있습니다. 아마도 복잡한 REGEXP를 작성하여 파일을 이름을 바꾸고 잘못된 문자를 제거해야하지만 UTL_FILE이 질식하는 지점을 모르므로 작동하지 않을지 확실하지 않습니다. 그것이 근원에 있다면, 그것은 도움이되지 않습니다. 다른 사람이이 문제를 겪었습니까? 다음은 스크립트입니다.UTL_FILE 스크립트를 사용한 파일 손상

DECLARE 

CURSOR C1 IS Select FILE_ID || '---' || substr(DOCUMENTLOCATION,1,instr 
(DOCUMENTLOCATION,'.')-1)||'.doc' as FILE_NAME, FILE_BLOB, FILE_ID 
From DOCUMENTS d inner join CASEJOURNAL c on d.FILE_ID = c.JOURNALENTRYID 
where (JOURNAL_ENTRY_TYPE = 117 or JOURNAL_ENTRY_TYPE = 3) AND 
c.DOCUMENTLOCATION Is Not Null AND d.MIME_TYPE = 'application/msword' 
AND FILE_ID BETWEEN 785 AND 3380; 

    l_file  UTL_FILE.FILE_TYPE; 
    l_buffer RAW(32000); 
    l_amount INTEGER := 32000; 
    l_pos  INTEGER := 1; 
    l_blob  BLOB; 
    l_blob_len INTEGER; 
    l_filename varchar2(255); 

BEGIN 
--Select BLOB file into variables 
FOR I in C1 
LOOP 
Select FILE_ID || '---' || substr(DOCUMENTLOCATION,1,instr 
(DOCUMENTLOCATION,'.')-1) ||'.doc' as FILE_NAME, FILE_BLOB INTO l_filename, 
l_blob From DOCUMENTS d inner join CASEJOURNAL c on d.FILE_ID = 
c.JOURNALENTRYID where (JOURNAL_ENTRY_TYPE = 117 or JOURNAL_ENTRY_TYPE = 
3) AND c.DOCUMENTLOCATION Is Not Null AND d.MIME_TYPE 
= 'application/msword' and d.FILE_ID = I.FILE_ID; 

-- Define the output directory 
l_file := UTL_FILE.FOPEN('\\myfiledirectory',l_filename,'wb',32000); 
l_pos := 1; 
l_amount := 32000; 

--Get length of BLOB file and save to variable. 
l_blob_len := DBMS_LOB.getlength(l_blob); 

-- Write the data to the file 
--If small enough for single write: 
    IF l_blob_len < 32000 THEN 
     UTL_FILE.PUT_RAW (l_file, l_blob); 
     UTL_FILE.FFLUSH(l_file); 
     --Write in pieces if larger than 32k 
     ELSE 
     l_pos := 1; 
     WHILE l_pos < l_blob_len AND l_amount > 0 
     LOOP 
     DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer); 
     UTL_FILE.PUT_RAW(l_file, l_buffer); 
     UTL_FILE.FFLUSH(l_file); 
     --Set start position for next write 
     l_pos := l_pos + l_amount; 
     --Set end position if less than 32k. 
     l_blob_len := l_blob_len - l_amount; 
      IF l_blob_len < 32000 THEN 
      l_amount := l_blob_len; 
      END IF; 
     END LOOP; 
    END IF; 
UTL_FILE.FCLOSE(l_file); 
END LOOP; 
END; 

답변

0

파일 이름은 파일이 열리면 바이트가 기록되는 방식에 영향을 미치지 않습니다. 32k가 넘으면 파일을 자르는 것 같습니다. 루프이 수행합니다

WHILE l_pos < l_blob_len AND l_amount > 0 
    LOOP 

...하지만 당신은 모두 l_pos 루프 내에서 l_blob_len을 변경; 조정 된 l_pos이하로 떨어지면l_blob_len을 종료하면 너무 일찍 루프를 종료합니다. l_blob_len을 조정할 필요가 없으며, 읽으려는 최대 바이트 수인 l_amount을 조정할 수도 있습니다. 왼쪽 것보다 높을지라도 상관 없습니다.

그래서에 루프를 변경 : 정말 문제와 관련되지

WHILE l_pos < l_blob_len AND l_amount > 0 
    LOOP 
     DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer); 
     UTL_FILE.PUT_RAW(l_file, l_buffer); 
     UTL_FILE.FFLUSH(l_file); 
     --Set start position for next write 
     l_pos := l_pos + l_amount; 
    END LOOP; 

,하지만 당신은 커서 루프 내부의 데이터를 다시 선택 할 필요가 없습니다. 당신은 이미 당신이 당신의 i 커서 변수에 필요한 값을 가지고, 그래서 당신은 할 수 있습니다 :

FOR I in C1 
LOOP 
l_filename := i.file_name; 
l_blob := i.file_blob; 

-- Define the output directory 
... 

을 또는 모두에 l_filenamel_blob 지역 변수와 귀찮게하지 않습니다; 커서 루프 내에서 참조 만하기 때문에 i.file_namei.file_blob을 어디에서나 직접 사용할 수 있습니다.

l_file := UTL_FILE.FOPEN('\\myfiledirectory',i.file_name,'wb',32000); 
l_blob_len := DBMS_LOB.getlength(i.file_blob); 

+0

UPDATE - 나는 추출물에 손상되고 있었다 파일이 없으며이 DB에 있던 명명 규칙에 내 스크립트와는 아무 관계가 없다는 것을 발견했다. 프론트 엔드 애플리케이션이 DB에 업로드 할 때 일부 파일을 압축하기 때문입니다. 압축 된 파일과 압축되지 않은 파일을 구분할 수있는 방법이 없었습니다 (DB에 플래그가 없습니다). 그러나 문제를 일으키는 파일에 UTL_FILE_COMPRESS.lz_uncompress()를 적용했을 때 완전히 열렸습니다. – kharvey