2026년 10월 07일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-29285 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-29285 file write error 는?
ORA-29285는 Oracle이 UTL_FILE 패키지나 외부 프로시저를 통해 파일에 데이터를 쓰는 도중 실패했을 때 발생하는 에러입니다. 주로 파일 시스템의 권한 문제, 디스크 공간 부족, 잘못된 파일 핸들 사용 등 다양한 원인으로 발생하며, PL/SQL 코드에서 UTL_FILE.PUT_LINE, UTL_FILE.PUT, UTL_FILE.NEW_LINE 등의 함수를 호출할 때 나타납니다. 이 에러는 운영 환경에서 로그 파일 생성, 데이터 익스포트, 배치 처리 결과 출력 등 파일 I/O가 필요한 모든 상황에서 발생할 수 있어 신속한 원인 파악과 대응이 필요합니다.
주요 발생 원인
1. 디스크 공간 부족 (Disk Full)
가장 흔하고 치명적인 원인 중 하나로, Oracle 서버가 파일을 쓰려는 디렉토리가 위치한 파티션의 디스크 공간이 꽉 찬 경우 발생합니다. 특히 대용량 데이터를 파일로 출력하는 배치 작업에서 자주 발생하며, 사전에 디스크 용량을 모니터링하지 않으면 운영 중 갑작스러운 장애로 이어질 수 있습니다. 로그 파일이 장기간 쌓여 파티션을 가득 채우는 경우도 매우 빈번하므로, 정기적인 파일 정리 정책이 필수입니다.
2. OS 파일 시스템 권한 문제 (File Permission Issue)
Oracle 프로세스를 실행하는 OS 계정(보통 oracle 계정)이 해당 디렉토리에 쓰기 권한이 없는 경우 발생합니다. 디렉토리 생성 후 권한 설정을 빠뜨리거나, 보안 정책 변경으로 인해 기존 권한이 박탈된 경우 이 에러가 발생합니다. 또한 Oracle Directory Object가 존재하더라도 실제 OS 레벨의 디렉토리 권한이 없으면 파일 쓰기가 불가능하므로 두 가지 모두 확인해야 합니다.
3. 잘못된 파일 핸들 또는 버퍼 초과 (Invalid File Handle / Buffer Overflow)
UTL_FILE.FOPEN으로 파일을 열 때 지정한 최대 라인 길이(max_linesize)를 초과하는 데이터를 쓰려 할 경우 발생합니다. 기본값은 1024바이트이며, 이를 초과하는 데이터를 한 번에 쓰면 ORA-29285 에러가 발생합니다. 또한 이미 닫혀 있는 파일 핸들에 데이터를 쓰려 시도하거나, FOPEN 없이 파일 핸들을 사용하는 경우에도 동일한 에러가 발생할 수 있습니다.
해결 방법
원인 1: 디스크 공간 부족 해결
먼저 OS 레벨에서 디스크 사용량을 확인하고, 불필요한 파일을 정리합니다.
-- Oracle 디렉토리 경로 확인
SELECT directory_name, directory_path
FROM dba_directories
ORDER BY directory_name;
-- 파일 쓰기 전 디스크 여유 공간 체크를 위한 예외 처리 포함 예제
DECLARE
v_file UTL_FILE.FILE_TYPE;
v_dir VARCHAR2(100) := 'DATA_EXPORT_DIR';
v_fname VARCHAR2(100) := 'export_' || TO_CHAR(SYSDATE, 'YYYYMMDD') || '.txt';
BEGIN
-- 파일 오픈 시도
v_file := UTL_FILE.FOPEN(v_dir, v_fname, 'W', 32767);
UTL_FILE.PUT_LINE(v_file, 'Start of Export: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
UTL_FILE.FCLOSE(v_file);
DBMS_OUTPUT.PUT_LINE('파일 쓰기 성공');
EXCEPTION
WHEN UTL_FILE.WRITE_ERROR THEN
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
RAISE_APPLICATION_ERROR(-20001, 'ORA-29285: 파일 쓰기 실패 - 디스크 공간 또는 권한을 확인하세요.');
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
RAISE;
END;
/
원인 2: 파일 권한 문제 해결
Oracle Directory Object와 OS 권한을 모두 설정해야 합니다.
-- 1단계: Oracle Directory Object 생성 (DBA 권한 필요)
CREATE OR REPLACE DIRECTORY DATA_EXPORT_DIR AS '/oracle/exports/data';
-- 2단계: 특정 사용자에게 읽기/쓰기 권한 부여
GRANT READ, WRITE ON DIRECTORY DATA_EXPORT_DIR TO app_user;
-- 권한 부여 확인
SELECT grantee, privilege, directory_name
FROM dba_tab_privs
WHERE table_name = 'DATA_EXPORT_DIR'
ORDER BY grantee;
-- 현재 사용자가 접근 가능한 디렉토리 목록 확인
SELECT directory_name, directory_path
FROM all_directories
ORDER BY directory_name;
# OS 레벨 권한 설정 (서버에서 root 또는 oracle 계정으로 실행)
mkdir -p /oracle/exports/data
chown oracle:oinstall /oracle/exports/data
chmod 755 /oracle/exports/data
# 권한 확인
ls -ld /oracle/exports/data
원인 3: 버퍼 크기 초과 해결
FOPEN 호출 시 max_linesize를 적절히 조정하고, 긴 데이터는 분할하여 씁니다.
DECLARE
v_file UTL_FILE.FILE_TYPE;
v_long_text VARCHAR2(32767);
v_chunk VARCHAR2(4000);
v_len NUMBER;
v_pos NUMBER := 1;
c_chunk_size CONSTANT NUMBER := 4000;
BEGIN
-- max_linesize를 32767로 최대 설정하여 오픈
v_file := UTL_FILE.FOPEN('DATA_EXPORT_DIR', 'large_data.txt', 'W', 32767);
-- 긴 텍스트 데이터 예시
v_long_text := RPAD('Oracle DBA Best Practice Data: ', 10000, 'X');
v_len := LENGTH(v_long_text);
-- 청크 단위로 분할하여 쓰기
WHILE v_pos <= v_len LOOP
v_chunk := SUBSTR(v_long_text, v_pos, c_chunk_size);
UTL_FILE.PUT(v_file, v_chunk);
v_pos := v_pos + c_chunk_size;
END LOOP;
UTL_FILE.NEW_LINE(v_file);
UTL_FILE.FFLUSH(v_file); -- 버퍼를 즉시 디스크에 반영
UTL_FILE.FCLOSE(v_file);
DBMS_OUTPUT.PUT_LINE('대용량 데이터 쓰기 완료');
EXCEPTION
WHEN UTL_FILE.WRITE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('파일 쓰기 에러 발생: max_linesize 확인 필요');
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
WHEN UTL_FILE.INVALID_MAXLINESIZE THEN
DBMS_OUTPUT.PUT_LINE('max_linesize 범위 초과 (1 ~ 32767)');
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
RAISE;
END;
/
예방 방법
1. 디스크 모니터링 및 자동 정리 정책 수립
디스크 사용률이 임계치(예: 80%)에 도달하면 DBA에게 알림을 발송하는 모니터링 스크립트를 구성하고, 오래된 로그 및 임시 파일을 주기적으로 자동 삭제하는 배치 작업을 운영 환경에 반드시 도입해야 합니다. 아래와 같이 Oracle의 Scheduler를 활용하여 파일 정리 작업을 자동화할 수 있습니다.
-- 파일 쓰기 전 디렉토리 존재 여부 및 접근 가능 여부를 체크하는 래퍼 프로시저
CREATE OR REPLACE PROCEDURE safe_file_write(
p_dir IN VARCHAR2,
p_filename IN VARCHAR2,
p_content IN VARCHAR2
) AS
v_file UTL_FILE.FILE_TYPE;
v_exists BOOLEAN;
v_flen NUMBER;
v_bsize NUMBER;
BEGIN
-- 파일 존재 여부 및 크기 사전 확인
UTL_FILE.FGETATTR(p_dir, p_filename, v_exists, v_flen, v_bsize);
v_file := UTL_FILE.FOPEN(p_dir, p_filename, 'A', 32767);
UTL_FILE.PUT_LINE(v_file, p_content);
UTL_FILE.FFLUSH(v_file);
UTL_FILE.FCLOSE(v_file);
EXCEPTION
WHEN UTL_FILE.WRITE_ERROR THEN
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
-- 에러 로그 테이블에 기록
INSERT INTO file_write_error_log (err_date, dir_name, file_name, err_msg)
VALUES (SYSDATE, p_dir, p_filename, 'ORA-29285: Write Error 발생');
COMMIT;
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(v_file) THEN
UTL_FILE.FCLOSE(v_file);
END IF;
RAISE;
END safe_file_write;
/
2. 파일 쓰기 코드에 견고한 예외 처리 및 표준 템플릿 적용
UTL_FILE을 사용하는 모든 PL/SQL 코드에 표준 예외 처리 템플릿을 적용하고, 팀 내 코딩 표준으로 지정하여 일관성을 유지해야 합니다. 파일 핸들은 반드시 EXCEPTION 블록에서도 닫히도록 처리하고, FFLUSH를 통해 버퍼 데이터가 즉시 디스크에 기록되도록 해야 합니다. 이를 통해 에러 발생 시 데이터 손실을 최소화하고 빠른 원인 파악이 가능합니다.
관련 에러
- ORA-29280: invalid directory path — Directory Object 경로 자체가 잘못된 경우
- ORA-29281: invalid file operation — 열려있지 않은 파일에 작업을 시도한 경우
- ORA-29282: invalid file ID — 잘못된 파일 ID를 사용한 경우
- ORA-29283: invalid file operation — 파일을 열 수 없거나 존재하지 않는 경우
- ORA-29284: file read error — 파일 읽기 중 오류 발생 (ORA-29285의 읽기 버전)
- ORA-29286: seek error — 파일 내 위치 이동 실패
- ORA-29287: invalid mode — FOPEN 시 잘못된 모드 지정 (‘R’, ‘W’, ‘A’ 외 값 사용)
이러한 에러들은 모두 UTL_FILE 패키지 사용 시 발생할 수 있으며, ORA-29285와 함께 발생하는 경우가 많으므로 UTL_FILE 관련 에러는 통합적으로 처리하는 것이 좋습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.