SQL*Loader

Database 2017.02.14 23:30

http://wiki.gurubee.net/display/STUDY/SQL*Loader



데이터 로딩과 언로딩

#데이터 로딩툴

  • SQL*Loader
  • External 테이블 : external 테이블은 운영체제 파일을 데이터베이스 테이블처럼 조회할 수 있는 기능(9i이상사용,10g이상 테이블의 데이터를 추출해서 운영체제 파일을 생성할 수도 있다.)

#데이터 언로딩 기술

  • flat file unload - 사용자가 정의한 포멧에 맞게 만들며 스프레드 시트와 같은 다른 유형에 호환가능한 결과도 만들수 있다.
  • data pump unload - 바이너리포멧으로서 데이터 펌프툴과 external 테이블로 접근할 수 있다.

SQLLDR는 매우 짧은 시간에 대용량의 데이터를 로드하는데 사용할 수 있고 2가지 모드가 있다.

1conventional path데이터를 로드하는데 sql insert를 사용
buffer cache를 거쳐서 data file에 쓰게 됨
2direct pathdirect path모드에서 sql을 사용하지 않고 직접 메모리에 data block을 만들어서 해당 table에 저장
플랫 파일의 데이터를 읽으면서 sql엔진을 거치지않는다
언두를 생성하지도 않으며 어떤 경우에는 리두 또한 생성하지 않는다
sqlldr 도움말
$sqlldr  

SQL*Loader: Release 11.2.0.3.0 - Production on 화 11월 27 19:13:38 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.


사용법: SQLLDR keyword=value [,키워드=값,...]

적절한 키워드:

    userid -- ORACLE 사용자 이름/비밀번호
   control -- 제어 파일 이름입니다.
       log -- 로그 파일 이름입니다.
       bad -- 부적합한 파일 이름입니다.
      data -- 데이터 파일 이름
   discard -- 폐기 파일 이름
discardmax -- 허용할 폐기 수  (기본값 all)
      skip -- 건너 뛸 논리 레코드 수  (기본값 0)
      load -- 로드할 논리 레코드 수  (기본값 all)
    errors -- 허용할 오류 수  (기본값 50)
      rows -- 기본 경로 바인드 배열 또는 직접 경로 데이터 저장 사이의 행 수
               (기본값: 규약 경로 64, 직접 경로 전체)
  bindsize -- 기본 경로 바인드 배열 크기(바이트)  (기본값 256000)
    silent -- 실행 중 메시지 숨기기(헤더,피드백,오류,폐기,분할 영역)
    direct -- 직접 경로 사용  (기본값 FALSE)
   parfile -- 매개변수 파일: 매개변수 사양을 포함하는 파일 이름
  parallel -- 병렬 로드 수행  (기본값 FALSE)
      file -- 확장 영역을 할당할 파일
skip_unusable_indexes -- 사용할 수 없는 인덱스 또는 인덱스 분할 영역 허용 안함/허용  (기본값 FALSE)
skip_index_maintenance -- 인덱스 유지 관리 안함, 영향을 받은 인덱스를 사용 불가로 표시  (기본값 FALSE)
commit_discontinued -- 로드가 중단되는 경우 로드된 행 커밋  (기본값 FALSE)
  readsize -- 읽기 버퍼 크기  (기본값 1048576)
external_table -- 로드를 위해 외부 테이블 사용: NOT_USED, GENERATE_ONLY, EXECUTE  (기본값 NOT_USED)
columnarrayrows -- 직접 경로 열 배열에 대한 행 수  (기본값 5000)
streamsize -- 직접 경로 스트림 버퍼 크기(바이트)  (기본값 256000)
multithreading -- 직접 경로에서 다중 스레드 사용
 resumable -- 현재 세션에 대한 재개를 사용 또는 사용 안함으로 설정합니다.  (기본값 FALSE)
resumable_name -- 재개 가능한 명령문 식별에 도움이 되는 텍스트 문자열
resumable_timeout -- RESUMABLE에 대한 대기 시간(초)  (기본값 7200)
date_cache -- 날짜 변환 캐시 크기(항목)  (기본값 1000)
no_index_errors -- 인덱스 오류 발생 시 로드 중단  (기본값 FALSE)

주: 명령행 매개변수는 위치 혹은 키워드로 지정될 수 있습니다.
위치 또는 키워드별입니다. 전자의 예는 'sqlldr
scott/tiger foo'; 후자의 예는 'sqlldr control=foo'
하나는 이전 위치에 의해 매개변수를 지정할 수 있으나 매개변수가
키워드에 의해 지정한 이후에는 할 수 없습니다.  예를 들어,
'sqlldr scott/tiger control=foo logfile=log'는 허용되지만
'sqlldr scott/tiger control=foo log'는
위치가 맞더라도 허용되지 않습니다

_참조 : http://docs.oracle.com/cd/E11882_01/server.112/e22490/ldr_params.htm#g1014550_

SQLLDR를 사용하기위해서는 contol file이 필요하다. 
컨트롤 파일에 포함 될 수 있는 내용

  • 입력 대상 테이블에 대한 정보
  • 레이아웃
  • 데이터타입등 입력 데이터를 설명하는 정보
  • 로드해야할 데이터

Control file 생성방법

1LOAD DATA
  • 데이터를 로드
2INFILE *
  • 컨트롤파일 자체내에 실제로드될 데이터가 있음을 알려줌,
  • 데이터가 포함된 다른 파일명을 지정할수도 있다 ex) INFILE demo.dat
3INTO TABLE
  • 로딩할 테이블(DEPT)
4FILEDS TERMINATED BY ','
  • 입력데이터를 구분할 방법(컬럼구분자)
5(DEPTNO,DNAME,LOC)
  • 입력될 데이터의 컬럼 순서와 필드길이 (char타입은 디폴트가 255)
    ex)(DEPTNO,DNAME char(1000),LOCL)
6BEGINDATA
  • sqlldr로 입력할 데이터의 설명부분이 끝난것과 실제데이터입력을 알람
710,SALES,VIRGINIA실제데이터
820,ACCOUNTING,VIRGINIA실제데이터
930,CONNSULTING,VIRGINIA실제데이터
1040,FINANCE,VIRGINIA실제데이터
TEST

control 파일(demo1.ctl) 생성

LOAD DATA
INFILE *
INTO TABLE dept
FIELDS TERMINATED BY ','
(
deptno
,dname
,loc
)
BEGINDATA
10,ACCOUNTING,NEW YORK
20,RESEARCH,DALLAS
30,SALES,CHICAGO
40,OPERATIONS,BOSTON

a. 빈 DEPR 테이블 생성(demo1.ctl라는 컨트롤파일을 사용하기위해)

SQL> create table dept
    (deptno number(2) constraint dept_pk primary key,
     dname  varchar2(14),
     loc    varchar2(13)
    )
    /
테이블이 생성되었습니다.

b. 명령어 실행

$sqlldr userid=hun/imsi00 control=C:\book\ch15\demo1.ctl
SQL*Loader: Release 11.2.0.3.0 - Production on 화 11월 27 20:28:02 2012
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
커밋 시점에 도달 - 논리 레코드 개수 4

c. 결과

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

d. 로그파일(demo1.log)

SQL*Loader: Release 11.2.0.3.0 - Production on 화 11월 27 20:28:02 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

제어 파일:    C:\book\ch15\demo1.ctl
데이터 파일:    C:\book\ch15\demo1.ctl
  부적합한 파일:     C:\book\ch15\demo1.bad
  폐기 파일:    지정 사항 없음

 (모든 폐기된 레코드 허용)

로드할 건수: ALL
생략 건수:  0
허용 오류수:  50
바인드 배열:  64 행, 최대 256000 바이트
계속:    지정 사항 없음
사용된 경로:      규약

테이블 DEPT, 로드되었습니다 개개의 논리 레코드로부터
이 테이블에 적당한 Insert 옵션: INSERT

   열 이름                        위치    Len   Term Encl 데이터유형
------------------------------ ---------- ----- ---- ---- ---------------------
DEPTNO                              FIRST     *   ,       CHARACTER            
DNAME                                NEXT     *   ,       CHARACTER            
LOC                                  NEXT     *   ,       CHARACTER            

테이블 DEPT:
  4 행 로드되었습니다.
  데이터 오류 때문에 0 행(이)가 로드되지 않았습니다   --오류가 발생해도 로그파일에서 확인 가능
  모든 WHEN절이 실패하여 0 행(이)가 로드되지 않았습니다
  모든 필드가 NULL이어서 0 행(이)가 로드되지 않았습니다


바인드 배열에 할당된 영역:             49536바이트(64 행)
읽기 버퍼 바이트: 1048576

생략된 논리 레코드의 합계:         0
읽어낸 논리 레코드의 합계:         4
거부된 논리 레코드의 합계:         0
폐기된 논리 레코드의 합계:         0

화 11월 27 20:28:02 2012에 실행 개시
화 11월 27 20:28:04 2012에 실행 종료

경과 시간:        00:00:02.24
CPU 시간:         00:00:00.05

#데이터 로딩과 관련한 SQLLDR FAQ

1. 로그파일의 '최대 길이 초과'가 왜 발생하는가?
2. 구분자를 포함하는 데이터 로드 방법
3. 고정 길이 포맷 데이터 로드 방법
4. 날짜 데이터 로드 방법
5. 함수를 사요한 데이터 로드 방법
6. 개행문자를 포함한 데이터 로드 방법
7. LOB 데이터 로드
8. lnline LOB 데이터 로딩
9. Out of Line LOB 데이터 로딩
10. 객체 컬럼에 LOB 데이터 로딩
11. 저장 프로시저에서 SQLLDR를 호출하는 방법

1. 로그파일의 '최대 길이 초과'가 왜 발생하는가?

Record 4:Rejected - Error on table DEPT, column DNAME.
field in data file exceeds maximun legnth

위의 오류는 입력 레크도를 처리하는 과정에서 SQLLDR의 기본 데이타타입인 char(255)를 초과하는 문자열 데이타타입이 입력되었기 때문.
char(255)를 초과하는 문자가 있다면 입력될 데이터의 컬럼 순서와 필드길이를 기술시 필드길이를 명시해 주어야한다.

2. 구분자를 포함하는 데이터 로드 방법

  • 1) 콤마로 구분 된 데이터
  • 2) 탭으로 구분된 데이터
TEST

1) 콤마로 구분 된 데이터

각 필드를 구분하기 위한 가장 일반적인 포멧은 CSV(comma-separated value)포맷이고 콤마로 필드 구분
만약에 문자열이 구분자를 포함하게 된다면(여기서는 ,로) 큰따옴표로 문자열을 감싸주면 된다.
그런데 문자열자체에 큰따옴표도 포함하게 된다면 '"'을 사용한다.

a. 컨트롤파일 수정

LOAD DATA
infile *
into table dept
fields terminated by ','
optionally enclosed by '"'
(DEPTNO,DNAME,LOC)
begindata
10,sales,"virginia,USA"
20,Accountiong,"va,""USA""" --구분자인 ,를 포함하는 문자열는 " " 로 감싸여져 있으면 "를 포함하는 문자열은 " "로 한번더 감싸주고 있다.
30,consulting,virginia
40,Finance,virginia

b. SQLLDR실행

$sqlldr userid=hun/imsi00 control=C:\book\ch15\demo1.ctl
SQL*Loader: Release 11.2.0.3.0 - Production on 화 11월 27 21:26:19 2012
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
커밋 시점에 도달 - 논리 레코드 개수 3
커밋 시점에 도달 - 논리 레코드 개수 4

c. 실행결과

SQL> select *from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 sales          virginia,USA
        20 Accountiong    va,"USA"  
        30 consulting     virginia
        40 Finance        virginia

2) 탭으로 구분된 데이터

  • 2가지 방법으로 구현
    1. FILEDS TERMINATED BY WHITESPACE
    2. FILEDS TERMINATED BY X'09' (16진수 포맷을 사용한 탭문자,ASCII에서 9는 탭문자)
1. FILEDS TERMINATED BY WHITESPACE

a. 컨트롤파일 수정

LOAD DATA
infile *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY WHITESPACE
(DEPTNO,DNAME,LOC)
BEGINDATA
10	sales	Virginia

b. SQLLDR실행

$sqlldr userid=hun/imsi00 control=C:\book\ch15\demo1.ctl

c. 실행결과

SQL> select *from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 sales          Virginia
2. FILEDS TERMINATED BY X'09'

a. 컨트롤파일 수정

LOAD DATA
infile *
INTO TABLE DEPT
REPLACE
FIELDS TERMINATED BY x'09'
(DEPTNO, dummy1 filler, DNAME, dummy2 filler, LOC)
BEGINDATA
10	sales	Virginia

b. SQLLDR실행

$sqlldr userid=hun/imsi00 control=C:\book\ch15\demo1.ctl

c. 실행결과

안됨(0개inset)

d. 실행로그

SQL*Loader: Release 11.2.0.3.0 - Production on 수 11월 28 16:38:22 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

제어 파일:    C:\book\ch15\demo1.ctl
데이터 파일:    C:\book\ch15\demo1.ctl
  부적합한 파일:     C:\book\ch15\demo1.bad
  폐기 파일:    지정 사항 없음

 (모든 폐기된 레코드 허용)

로드할 건수: ALL
생략 건수:  0
허용 오류수:  50
바인드 배열:  64 행, 최대 256000 바이트
계속:    지정 사항 없음
사용된 경로:      규약

테이블 DEPT, 로드되었습니다 개개의 논리 레코드로부터
이 테이블에 적당한 Insert 옵션: REPLACE

   열 이름                        위치    Len   Term Encl 데이터유형
------------------------------ ---------- ----- ---- ---- ---------------------
DEPTNO                              FIRST     *  WHT      CHARACTER            
DUMMY1                               NEXT     *  WHT      CHARACTER            
  (FILLER FIELD)
DNAME                                NEXT     *  WHT      CHARACTER            
DUMMY2                               NEXT     *  WHT      CHARACTER            
  (FILLER FIELD)
LOC                                  NEXT     *  WHT      CHARACTER            

레코드 1: 기각됨 - 테이블 DEPT, 열 DUMMY2에 오류
논리 레코드가 종료하기 전에 열을 찾지 못했습니다 (TRAILING NULLCOLS 사용)
테이블 DEPT:
  0 행 로드되었습니다.
  데이터 오류 때문에 1 행(이)가 로드되지 않았습니다
  모든 WHEN절이 실패하여 0 행(이)가 로드되지 않았습니다
  모든 필드가 NULL이어서 0 행(이)가 로드되지 않았습니다


바인드 배열에 할당된 영역:             49536바이트(64 행)
읽기 버퍼 바이트: 1048576

생략된 논리 레코드의 합계:         0
읽어낸 논리 레코드의 합계:         1
거부된 논리 레코드의 합계:         1
폐기된 논리 레코드의 합계:         0

수 11월 28 16:38:22 2012에 실행 개시
수 11월 28 16:38:22 2012에 실행 종료

경과 시간:        00:00:00.05
CPU 시간:         00:00:00.01

3. 고정 길이 포맷 데이터 로드 방법

  • SQLLDR로 로드하는 데 최적의 데이터 포멧
  • 가장 빠른 로드 방법일 것.
  • 로드해야할 데이터가 대용량이라면, 고정 위치 포맷으로 변환하는 것이 가장 최상의 방법
  • 구분자를 갖는 파일보다 크기가 훨씬 클 수 있다.
    TEST

    a. entire_line 필드 추가

    SQL> alter table dept add entire_line varchar2(29);
    

    b. 컨트롤파일 수정

    LOAD DATA
    infile *
    into table dept
    replace
    (DEPTNO position(1:2),     -- 고정위치 데이터를 로드하기 위해서 position 키워드를 사용해야한다.
    DNAME position(*:16),      -- *는 바로앞 필드가 끝난 위치를 기준으로 1바이트 추가된 지점 (여기에선  * =3)
    LOC position(*) char(13),  -- 각 필드의 길이를 명시해 줄 수도 있다.
    ENTIRE_LINE position(1:29) -- position절을 이용해서 구분자 없이 각 필드를 바이트로 계산해서 데이터를 임포트 할수도있다
    )                           
    begindata
    10Accounting virginia,USA
    

    c. SQLLDR실행 후 결과

    SQL> select *from dept;
    
        DEPTNO DNAME          LOC           ENTIRE_LINE
    ---------- -------------- ------------- -----------------------------
            10 Accounting vir ginia,USA     10Accounting virginia,USA
    

4. 날짜 데이터 로드 방법

  • 날짜를 로딩하는 방법은 컨트롤 파일 내에 date 테이터타입을 사용해서 date mask를 명시할 수 있다.
TEST

a. last_updated 필드 추가

SQL> alter table dept add last_updated date;

b. 컨트롤파일 수정

LOAD DATA
infile *
into table dept
replace
fields terminated by ','
(DEPTNO,
DNAME,
LOC,
LAST_UPDATED date 'dd/mm/yyyy' -- date mask는 데이터베이스에서 to_char와 to_date를 사용한 것과 같은 mask이다.
)
begindata
10,salels,vig6inia,1/5/2000
20,Accounting,viginia,21/6/1999
30,Consulting,viginia,5/1/2000
40,Finance,viginia,15/3/2001

c. SQLLDR실행 후 결과

SQL> select *from dept;

    DEPTNO DNAME          LOC           ENTIRE_LINE                   LAST_UPD
---------- -------------- ------------- ----------------------------- --------
        10 salels         vig6inia                                    00/05/01
        20 Accounting     viginia                                     99/06/21
        30 Consulting     viginia                                     00/01/05
        40 Finance        viginia                                     01/03/15

5. 함수를 사용한 데이터 로드 방법

  • 함수를 사용할때는 반드시 SQL엔진을 경유해야 되기 때문에 direct path에서는 작동하지 않는다.
TEST

a. 컨트롤파일 수정

LOAD DATA
infile *
into table dept
replace
fields terminated by ','
TRAILING NULLCOLS	              -- NULL 허용 옵션
(DEPTNO,
DNAME "upper(:dname)",          -- 함수를 적용시키려면 " "를 추가하면 된다.
LOC "upper(:loc)",
LAST_UPDATED date 'dd/mm/yyyy'
)
begindata
10,salels,vig6inia,1/5/2000
20,Accounting,viginia,21/6/1999
30,Consulting,viginia,5/1/2000
40,Finance,viginia,15/3/2001

b. SQLLDR실행 후 결과

SQL> select *from dept;

    DEPTNO DNAME          LOC           ENTIRE_LINE                   LAST_UPD
---------- -------------- ------------- ----------------------------- --------
        10 SALELS         VIG6INIA                                    00/05/01  --dname,과 loc컬럼이 대문자로 입력
        20 ACCOUNTING     VIGINIA                                     99/06/21
        30 CONSULTING     VIGINIA                                     00/01/05
        40 FINANCE        VIGINIA                                     01/03/15

6. 개행문자를 포함한 데이터 로드 방법(p855)

  • 오라클 8.1.6이상 버전에서 내장된 개행문자를 처리하는 옵션들
    1) 개행문자 대신 다른 문자를 사용 - 문장에 개행문자가 있을 때마다 \n을 넣음(\n을 CHR(10)으로 대체하는 SQL함수 사용)
    2) FIX 속성 사용 - 고정길이 플랫 파일 로드
    3) VAR 속성 사용 - 각 줄의 첫 몇 바이트가 그줄에 해당하는 길이를 명시하는 포맷을 사용
    4) STR 속성 사용 - 가변 길이 파일 로드
1) 개행문자 대신 다른 문자를 사용

a. comments 필드 추가

SQL> alter table dept add comments varchar2(4000);

a. 컨트롤파일 수정

LOAD DATA
infile *
into table dept
replace
fields terminated by ','
TRAILING NULLCOLS	              -- NULL 허용 옵션
(DEPTNO,
DNAME "upper(:dname)",          -- 함수를 적용시키려면 " "를 추가하면 된다.
LOC "upper(:loc)",
COMMENTS "replace(:comments,'\\n',chr(10))"   -- \n을 두개의 문자열이 아닌 개행문자로 변환
)
begindata
10,salels,viginia,This is the sales\nOffice in virginia
20,Accounting,viginia,This is the Accounting\nOffice in Virginia
30,Consulting,viginia,This is the Consulting\nOffice in Virginia
40,Finance,viginia,This is the Finance\nOffice in VIrginia

b. SQLLDR실행 후 결과

hun@SOLTEST> select deptno, dname, comments from dept;

    DEPTNO DNAME          COMMENTS
---------- -------------- -------------------------------------------------------------
        10 SALELS         This is the sales               
                          Office in virginia

        20 ACCOUNTING     This is the Accounting
                          Office in Virginia

        30 CONSULTING     This is the Consulting
                          Office in Virginia

        40 FINANCE        This is the Finance
                          Office in VIrginia
2) FIX 속성 사용

a. 컨트롤파일 수정

LOAD DATA
infile demo.dat "fix 80"    -- 입력데이터 파일이 각각 80바이트 레코드를가짐
into table dept
replace
fields terminated by ','
TRAILING NULLCOLS	              
(DEPTNO,
DNAME "upper(:dname)",          
LOC "upper(:loc)",
COMMENTS 
)

b. 8진수로변환한 dump파일 확인

r3_qas:/>od -c -w10 -v demo.dat                     -- od :8진수로 변환, -w10: 10개의 문자열만 출력
0000000    1   0   ,   s   a   l   e   l   s   ,
0000012    v   i   g   i   n   i   a   ,   T   h
0000024    i   s       i   s       t   h   e    
0000036    s   a   l   e   s   \   n   O   f   f
0000050    i   c   e       i   n       v   i   r
0000062    g   i   n   i   a  \n  
0000074    
0000106    
0000120    2   0   ,   A   c   c   o   u   n   t 
0000132    i   n   g   ,   v   i   g   i   n   i 
0000144    a   ,   T   h   i   s       i   s     
0000156    t   h   e       A   c   c   o   u   n 
0000170    t   i   n   g   \   n   O   f   f   i 
0000202    c   e       i   n       V   i   r   g 
0000214    i   n   i   a      \n                 
0000226    
0000240    3   0   ,   C   o   n   s   u   l   t   
0000252    i   n   g   ,   v   i   g   i   n   i   
0000264    a   ,   T   h   i   s       i   s       
0000276    t   h   e       C   o   n   s   u   l   
0000310    t   i   n   g   \   n   O   f   f   i   
0000322    c   e       i   n       V   i   r   g   
0000334    i   n   i   a      \n                   
0000346    
.
.
.


c. SQLLDR실행 후 결과

hun@SOLTEST> select '"' || comments || '"' from dept;

COMMENTS
-------------------------------------------------------------
"This is the sales               
Office in virginia                           "

"This is the Accounting
Office in Virginia                       "

"This is the Consulting
Office in Virginia                       "

"This is the Finance
Office in VIrginia                          "
3) VAR 속성 사용

a. 컨트롤파일 수정

LOAD DATA
infile demo.dat "var 3"         -- 첫 번째 3바이트는 입력 레코드의 길이를 의미
into table dept
replace
fields terminated by ','
TRAILING NULLCOLS	              -- NULL 허용 옵션
(DEPTNO,
DNAME "upper(:dname)",          -- 함수를 적용시키려면 " "를 추가하면 된다.
LOC "upper(:loc)",
COMMENTS 
)

b. demo.dat 파일수정

 5610,Sales,Virginia,This is the Sales          --56바이트 , 유닉스에서는 056으로 
Office in Virginia
 6620,Accounting,viginia,This is the Accounting
Office in Virginia 
 6630,Consulting,viginia,This is the Consulting
Office in Virginia 
 6040,Finance,viginia,This is the Finance
Office in VIrginia      

c. SQLLDR실행 후 결과

...
4) STR 속성 사용
  • 내장된 개행문자를 가진 데이터를 로드하는 데 가장 유연한 방법
  • 각 줄의 끝에 특수문잘르 가진 입력 파일 생성하여 사용할 수 있게 해준다.

a. STR확인

select utl_raw.cast_to_raw('|'||chr(10)) from dual;              -- 유닉스에서 줄의종결표시는 chr(10), 특수문자표시는 | 라고 가정했을때
utl_raw.cast_to_row('|'||chr(10))
----------------------------------
7C0A                                                             -- STR = 7C0A

select utl_raw.cast_to_raw('|'||chr(13)||chr(10)) from dual;     -- 윈도우에서 줄의종결표시는 chr(10), 특수문자표시는 | 라고 가정했을때
UTL_RAW.CAST_TO_RAW('|'||CHR(13)||CHR(10))
-----------------------------------------------------------
7C0D0A                                                           -- STR = 7C0D0A

b. 컨트롤파일 수정

LOAD DATA
infile demo.dat "str X'7C0A'"         -- 첫 번째 3바이트는 입력 레코드의 길이를 의미
into table dept
replace
fields terminated by ','
TRAILING NULLCOLS	              -- NULL 허용 옵션
(DEPTNO,
DNAME "upper(:dname)",          -- 함수를 적용시키려면 " "를 추가하면 된다.
LOC "upper(:loc)",
COMMENTS 
)

b. demo.dat 파일수정

10,Sales,Virginia,This is the Sales         
Office in Virginia|
20,Accounting,viginia,This is the Accounting
Office in Virginia|
30,Consulting,viginia,This is the Consulting
Office in Virginia|
40,Finance,viginia,This is the Finance
Office in VIrginia|

c. SQLLDR실행 후 결과

SQL> select deptno, comments from dept;

    DEPTNO COMMENTS
---------- --------------------------------------
        10 This is the Sales
           Office in Virginia

        20 This is the Accounting
           Office in Virginia

        30 This is the Consulting
           Office in Virginia

        40 This is the Finance
           Office in VIrginia

7. LOB 데이터 로드

  • LOB : BLOB,CLOB 데이터타입
  • LOB필드 로딩하기 위한 방법
    1) PL/SQL(DBMS_LOB패키지 사용)
    2) SQLLDR

1) PL/SQL로 LOB로딩

  • BFILE을 사용할 수 있도록 해주는 DBMS_LOB 패지지 프로시저(DB내에서 BLOB,CLOB컬럼으로 데이터를 옮기기 위해 운영체제 파일을 읽을수있도록해줌)
    LoadFromFile 
    LoadBLOBFromFile : BLOB컬럼에 로드된 데이터의 범위를 가리키는 프로시저 파라미터 후반부의 OUT파라미터를 제외하고 LoadFromFile과 차이가없다.
    LoadCLOBFromFile : LoadCLOBFromFile 루틴은 캐릭터 셋 변환 기능
    _DBMS_LOB참조:http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_lob.htm#ARPLS600_
DBMS_LOB 패키지 프로시저 사용방법
1. DB에 DIRECTORY 객체 생성
  • 필요한 권한 : CREATE ANY DIRECTORY
     
    create or replace directory dir1 as '/tmp/';
    create or replace directory "dir2" as '/tmp/';   -- "dir2" => 대소문자 구분
    

2) BLOB or CLOB에 데이터를 로드

a. demo table 생성

create table demo
  ( id	int primary key,
	  theClob clob
	)
	

/

b. test.txt 파일 생성

host echo 'Hello World\!'>/tmp/test.txt

c. dbms_lob 패키지로 파일 업로드

declare
		l_clob clob;
		l_bfile bfile;
begin
		insert into demo values( 1, empty_clob() )          -- CLOB을 EMPTY_CLOB()로 초기화
		returning theClob into l_clob;
		l_bfile := bfilename( 'DIR1', 'test.txt');          -- BFIEL 객체 생성
		dbms_lob.fileopen(l_bfile);                         -- LOB를 OPEN 함으로써 LOB를 읽을 수 있다.
		dbms_lob.loadfromfile(l_clob, l_bfile,              -- INSERT했던 LOB locator에 운영체제파일 /tmp/test.txt의 전체내용을 로드
		                dbms_lob.getlength(l_bfile));       -- DBMS_LOB.GETLENGTH()를 사용해서 BFILE에 로드된 전체 바이트수를 LOADFROMFILE()루틴에 전달
		dbms_lob.fileclose(l_bfile);                        -- CLOB을 로드하고 BFILE CLOSE
end;
/
d. 수행 결과 학인
sys@BWD> select dbms_lob.getlength(theClob), theClob from demo;

DBMS_LOB.GETLENGTH(THECLOB) THECLOB
--------------------------- --------------------
                         13 Hello World!

2) SQLLDR로 LOB 데이터 로딩

1) inline 데이터인경우(LOB데이터가 다른 데이터 로우와 같은블록에 저장되는 경우)
2) out of line(LOB 데이터가 LOB세그먼트에 저장되는 경우) , SDF(secondary data file) 이라고도 함

8. lnline LOB 데이터 로딩

  • LOB는 일반적으로 개행문자와 특수문자를 포함하고있다.
  • 개행문자를 포함한 데이터 로드방법에서 다뤘던 네가지 방법중 하나로 TEST

a. DEPT테이블의 COMMENTS 컬럼을 큰 VARCHAR2필드 대신에 CLOB으로 수정

truncate table dept;
alter table dept drop column comments;
alter table dept add comments clob;

b. demo.dat 파일 수정

10,Sales,Virginia,This is the Sales         
Office in Virginia|
20,Accounting,viginia,This is the Accounting
Office in Virginia|
30,Consulting,viginia,This is the Consulting
Office in Virginia|
40,Finance,viginia,"This is the Finance
Office in VIrginia, it has embedded comas and is 
much longer than the other comments field. If you
feel the need to add double quoted text in here like
this: ""You will need to double up those quotes!"" to
preserve them in the stirng. This field keeps going for up to
1000000 bytes (because of the control file definition I Used)
or until we hit the magic end of record marker,
the | followed by an end of line - it is right here ->"|

c. 컨트롤 파일 수정

LOAD DATA
infile demo.dat "str X'7C0D0A'"        
into table dept
replace
fields terminated by ',' optionally enclosed by '"'
TRAILING NULLCOLS	             
(DEPTNO,
DNAME "upper(:dname)",         
LOC "upper(:loc)",
COMMENTS char(1000000)
)

d. 수행결과

COMMENTS
------------------------------------------------------------
This is the Sales
Office in Virginia

This is the Accounting
Office in Virginia

This is the Consulting
Office in Virginia

This is the Finance
Office in VIrginia, it has embedded comas and is 
much longer than the other comments field. If you
feel the need to add double quoted text in here like
this: "You will need to double up those quotes!" to
preserve them in the stirng. This field keeps going for up to
1000000 bytes (because of the control file definition I Used)
or until we hit the magic end of record marker,
the | followed by an end of line - it is right here ->

9. Out of Line LOB 데이터 로딩

  • 로드해야 할 LOB 데이터 파일의 이름만 있는것(한 테이블 내에 구조화 된 데이터와 LOB 데이터가 함께있는게 아님)
  • LOBFILE - 개행문자를 처리하는 방법보다 더 많은 유연성을 제공

LOBFILE 포멧

  • 고정길이 필드( 예를들어 LOBFILE로 부터 100에서 1000바이트를 로드)
  • 구분자를 가진 필드( enclosed by 구분자 또는 terminated by 구분자) – 가장 일반적인 형태
  • 길이와 값을 가진 가변 길이 필드
TEST

a.lob_demo table 생성

create table lob_demo
(	owner 			varchar2(255),
	time_stamp  date,
	filename 	  varchar2(255),
	data				blob
)
/

b. 컨트롤 파일 수정

LOAD DATA
INFILE *
REPLACE
INTO TABLE LOB_DEMO
(	owner 			position(17:25),
	time_stamp	position(44:55) date "MON DD HH24:MI",
	filename		position(57:100),
	data				LOBFILE(filename) TERMINATED BY EOF
)
BEGINDATA
-rwxr-xr-x    1  oraqas   dba      3380 Nov 16 16:04     .dbenv_r3_qas.csh
-rwxr-xr-x    1  oraqas   dba      3380 Nov 16 16:04     .dbenv_r3_qas.sh
-rw-r--r--    1  oraqas   dba      3375 Aug 16 09:52     .dbenv_r3dev.sh
-rw-r--r--    1  oraqas   dba      3363 Aug 16 09:52     .dbenv_r3prddb.csh
-rw-r--r--    1  oraqas   dba      3377 Aug 16 09:52     .dbenv_r3prddb.sh
-rwxrwxrwx    1  oraqas   dba       175 Nov 16 16:04     .dbsrc_r3_qas.csh
-rwxrwxrwx    1  oraqas   dba       158 Nov 16 16:04     .dbsrc_r3_qas.sh
-rw-r--r--    1  oraqas   dba       158 Aug 16 09:52     .dbsrc_r3dev.sh
-rw-r--r--    1  oraqas   dba       175 Aug 16 09:52     .dbsrc_r3prddb.csh
-rw-r--r--    1  oraqas   dba       158 Aug 16 09:52     .dbsrc_r3prddb.sh

c. 실행 결과

OWNER
-------

10. 객체 컬럼에 LOB 데이터 로딩

  • LOB와 복합객체 타입을 가진 테이블에 데이터를 로드
  • 복합객체타입은 이미지처리를 사용할 때 가장많이 나타난다.
  • 이미지 처리는 복합 객체 타입인 ORDSYS.ORDIMAGE를 사용해서 실행
TEST

a. image_load 테이블 생성

create table image_load(
id number,
name varchar2(255),
image ordsys.ordimage
)
/

hun@SOLTEST> desc image_load;
 이름                                                  널?      유형
 ----------------------------------------------------- -------- ------------------------------------
 ID                                                             NUMBER
 NAME                                                           VARCHAR2(255)
 IMAGE                                                          ORDSYS.ORDIMAGE

desc ordsys.ordimage;
인수명                         유형                    기본 내부/외부?
------------------------------ ----------------------- --------- --------
CTX                            RAW                     IN/OUT
LOCAL_DATA                     BLOB                    IN/OUT NOCOPY
SOURCE_TYPE                    VARCHAR2                IN
SOURCE_LOCATION                VARCHAR2                IN
SOURCE_NAME                    VARCHAR2                IN
FORMAT                         VARCHAR2                OUT
MIME_TYPE                      VARCHAR2                OUT
.
.
.
 
 desc ordsys.ordsource;
 NAME               Null? Type
 ------------------ ----- --------------
 LOCALDATA  							BLOB
 SRCTYPE  								VARCHAR2(4000)
 SRCLOCATION  						VARCHAR2(4000)
 SRCNAME 							  	VARCHAR2(4000)
 .
 .
 .
 

a. 컨트롤파일 수정

 LOAD DATA
 INFILE *
 INTO TABLE image_load
 REPLACE
 FIELDS TERMINATED BY ','
 ( ID,
 	 NAME,
 	 file_name FILLER,
 	 IMAGE column object                                  -- 컬럼의 이름이 아닌 컬럼 이름의 일부라는것을 SQLLDR에 알려준다.
 	 (
 	 		SOURCE column object
 	 		(
 	 			LOCALDATA LOBFILE(file_name) TERMINATED BY EOF
 	 								NULLIF file_name ='NONE'              -- SQLLDR에 FILE_NAME필드가 NONE문자를 포함한경우, 객체컬럼에 NULL을 로드하도록한다.
 	 		)
 	 )
 )
 BEGINDATA
 1,icons,icons.gif
 I have introduced two new constructs here:
 
begin
		for c in (select * from image_load) loop
			c.image.setproperties;  -- SETPROPERTIES는 ORDSYS.ORDIMAGE타입으로 제공되는 이미지 자체를 처리하고, 객체의 나머지 속성을 적합한 값으로 변경하는 객체메서드
		end loop;
	end;
/

11. 저장 프로시저에서 SQLLDR를 호출하는 방법

  • 저장 프로시저에서는 SQLLDR을 호출할 수 없다.

#SQLLDR 사용 시 주의사항

1. TRUNCATE가 다르게 동작하는 것처럼 보이는 현상

truncate table t reuse storage
  • reuse storage 옵션은 free space라는 표시만 해두고 할당된 익스텐트를 반환하지 않는다.

2. SQLLDR 기본값은 CHAR(255)

Record N: Rejected - Error on table T, column C.
Field in data file exceeds maximum length
  • SQLLDR의 기본 데이터 타입과 길이가 CHAR(255), 더길게사용했을때 발생

3. 명령어는 컨트롤 파일보다 더 우선시됨

  • SQLLDR의 다양한 옵션은 컨트롤 파일 내 또는 명령어 라인에 사용할 수 있다. ex)DATA=FILENAME, INFILE FILENAME
  • 명령어는 컨트롤 파일내의 어떠한 옵션보다 우선시 되기때문에 컨트롤 파일내의 실제 사용된 옵션만을 믿어서는 안된다.

#SQLLDR 정리

  • 데이터 로딩의 많은 영역과 일반적으로 발생하는 문제를 다루었다.
  • direct path로더를 사용한 대용량 데이터 로드에 대해 간단히 언급했다.
  • SQLLDR를 사용할 때 자주 발생하는 문제의 답을 제시했다.

문서정보


신고
Posted by steloflute

http://devyongsik.tistory.com/61


김세곤은 JSP Bible 책의 저자이며, 인프니스 사장이다.



출처 Good Luck !! | 크라임랩
원본 http://blog.naver.com/erfile/100008279019

원 출처가 어딘지 모르는..걍 떠돌아 다니는 글인데 클래스패스 땜에 컴퓨터를 뽀사버릴려다가 찾아서 퍼옴..

누군지 모르지만 김세곤 쌤.. 감사합니다..^^;;


---------------------------------------------------------------------------------------


클래스패스와 환경 변수, 그것이 알고 싶다.
김세곤 
2001년 4월 17일


서론
초보 자바 프로그래머를 괴롭히는 큰 문제 중에 그놈의 클래스패스는 빠지지 않는다. 클래스패스는 사실 이렇게 하나의 글로 설명하기조차 매우 부끄러운 사소한 것인데, 초보 자바 프로그래머에게는 절대 사소하지 않은 것이 현실이다. 더군다나, 가슴 아프게도 대부분의 자바 관련 서적은 클래스패스에 지면을 할애할 만한 형편도 안되고, 대부분의 저자들이 별것도 아닌 것에 공들여 설명하려 하지 않기 때문에, 당연히 클래스패스에 대해서는 많은 독자들이 제대로 이해하지 못한 채 끙끙댄다. 한편으로는, 이것은 기초를 제대로 다지지 않은 독자들의 책임이 크다. 클래스패스를 잘 설정해서 자바 프로그램을 컴파일하고 실행하는 기술은 자바 언어의 첫번째 단추이고, 이 내용은 대부분의 자바 책(자바 관련 서적이 아닌 자바 그 자체를 설명하는 책)에서는 설명이 되어 있기 때문이다.

필자는 JSP Bible이라는 책을 집필하고 독자로부터 많은 질문을 받았는데, 거짓말 보태지 않고 50% 이상의 독자가 클래스패스로 골머리를 썩고 있었다. JSP로 웹 개발을 시도하려 한다면 자바 언어의 첫번째 단추인 클래스패스와 컴파일 정도에는 문제가 없어야 하는데, 아쉽게도 이 첫번째 단추를 못 껴서 진도를 못 나가다니 가슴 아픈 현실이 아닐 수 없다.

가장 좋은 방법은 역시 자바 언어를 제대로 공부하고 나서 JSP, Servlet, EJB 등 그 다음 단계의 공부를 진행하는 것이다. 그런데, 이유야 어찌 됐건, 대부분의 독자들은 자바에 대한 기초없이 응용 단계인 JSP, Servlet, EJB 등으로 마구 앞질러 나간다. 그리고, 막히면 다시 자바 언어를 체계적으로 공부하지 않고, 끙끙거리며 당장 진도를 나가려고 발버둥친다. 이 대목에서 찔리는 독자 여러분들이 분명히 많을 것이다.

솔직히 말해서, 필자는 JSP Bible 집필 당시에 자바의 생기초라 할 수 있는 클래스패스 설정하기 및 컴파일하기 등에 대해서 이렇게 많은 독자들이 모르리라고 예상하지 못했다. 그리고, 끊임없이 클래스패스에 대한 질문을 받으면서, 같은 답변을 계속 하다보니 이제는 클래스패스에 대한 질문만 만나면 경기가 난다.

필자는 이 글로 더 이상 클래스패스나 환경 변수 혹은 컴파일하기 등에 관련된 질문이 없기를 간절히 기대한다. 더 나아가서 많은 자바를 공부하고자 하는 개발자들이 제발 자바 언어에 대해서는 탄탄하게 기초를 다졌으면 한다.


클래스 이름과 패키지
갑돌이가 A.java 라는 자바 프로그램을 만들었다고 하자. 그리고, 자신의 컴퓨터 C 드라이브의 myClass라는 폴더에 A.java를 컴파일한 A.class를 넣어 두었다고 치자. 그리고는 A.class를 잘 사용하다가 어느날 똑순이가 만든 클래스를 사용할 일이 있어서 똑순이의 클래스들을 건네 받았는데, 그 중에 A.class라는 같은 이름의 클래스가 있다는 사실을 알았다. 갑돌이는 갑자기 답답해졌다. 자, 어찌 하면 갑돌이가 만든 클래스 A와 똑순이가 만든 클래스 A를 구별할 수 있을까?

해답은 바로 패키지이다.

갑돌이의 회사는 gabdol이고, 똑순이의 회사는 ddogsun이므로, 이 이름을 클래스 이름 A에 붙여쓰면 구별이 될 수가 있는 것이다. 갑돌이의 클래스 A의 이름을 gabdol.A로 똑순이의 클래스 A의 이름을 ddogsun.A로 사용하면 고민이 해결된다는 말이다. 그런데, 덕팔이의 회사 이름이 갑돌이의 회사 이름과 같다면 또 이름이 충돌하게 된다. 그렇다면 전세계에서 유일한 이름을 클래스 이름 앞에 붙여주면 아주 간단해진다. 전세계에서 유일한 이름으로는 머리속에 팍 떠오르는 것이 회사의 도메인 명이다. 갑돌이네 회사가 www.gabdol.com이라는 도메인 이름을 소유하고 있다면, 갑돌이네 회사에서 만드는 모든 클래스의 이름을 com.gabdol.A와 같은 식으로 만들면 문제가 해결된다. 바로, 이 com.gabdol이 클래스 A의 패키지 이름이 되는 것이다. 만일, 갑돌이네 회사가 두 개의 자바 소프트웨어를 개발했는데, 둘 다 A.java라는 클래스가 있다면 이를 또 구별해야 한다. 이런 경우라면 com.gabdol 뒤에 임의로 갑돌이네 회사가 알아서 패키지 이름을 만들면 된다. 두 개의 소프트웨어 이름이 sw1, sw2라고 하면 com.gabdol.sw1.A, com.gabdol.sw2.A 식으로 클래스 이름을 사용하는 것이다.

이렇게 패키지를 사용하게 되면 이름 충돌의 문제도 해결할 수 있을 뿐만 아니라, 클래스를 분류하기도 쉽다. 예를 들어, 갑돌이네 회사에서 고객에 관련된 클래스들의 패키지 이름을 com.gabdol.client로 하고, 상품에 관련된 클래스들의 패키지 이름을 com.gabdol.product로 정하면 클래스들의 성격을 패키지 이름만 보고도 쉽게 파악할 수 있는 것이다.


클래스의 위치
이제, 갑돌이가 만드는 클래스의 이름이 com.gabdol.sw1.A로 정해졌다고 하자. 그렇다면 이 클래스는 어디에 위치해야 할까? com.gabdol.sw2.A와 같은 폴더에 존재하면 안 되므로, 패키지 이름에 따라 클래스의 위치가 유일하게 구별될 수 있어야 한다. 갑돌이는 자신의 클래스르 모두 C:\myClass라는 폴더에 두고 있으므로, com.gabdol.sw1.A 클래스는 C:\myClass\com\gabdol\sw1 폴더에 두고, com.gabdol.sw2.A 클래스는 C:\myClass\com\gabdol\sw2 폴더에 두면 두 클래스가 충돌하지 않을 것이다. 이렇게 하면, 소스 파일과 컴파일된 클래스 파일이 다음처럼 위치하게 된다.

C:\myClass\com\gabdol\sw1\A.java
C:\myClass\com\gabdol\sw1\A.class
C:\myClass\com\gabdol\sw2\A.java
C:\myClass\com\gabdol\sw2\A.class


이제, 패키지의 이름에 따른 클래스의 위치에 대해서 감이 오는가?


패키지 선언과 임포트
com.gabdol.sw1.A 클래스의 패키지는 com.gabdol.sw1이고 com.gabdol.sw2.A 클래스의 패키지는 com.gabdol.sw2이다. 이 정보는 당연히 두 소스 코드 내에 들어가야 한다. 방법은 간단하다. C:\myClass\com\gabdol\sw1\A.java 코드의 첫머리에 다음의 한 줄만 쓰면 된다.


package com.gabdol.sw1;


여기서, com.gabdol.sw1.A 클래스가 com.gabdol.sw2 패키지에 들어있는 클래스들을 사용하고 싶다고 하자. 어떻게 해야 할까? 방법은 두 가지이다.

첫번째는 클래스의 이름을 완전히 써 주는 것이다. 다음처럼 말이다.


package com.gabdol.sw1;
...
com.gabdol.sw2.B b = new com.gabdol.sw2.B();
...


이렇게 하면 클래스 B가 com.gabdol.sw2 패키지 내에 있는 것이 드러나므로 컴파일 시에 문제가 없다.

두번째는 패키지를 임포트(import)하는 것이다. 다음처럼 하면 된다.


package com.gabdol.sw1;
import com.gabdol.sw2.*;
...
B b = new B();
...


위의 코드의 import com.gabdol.sw2.*; 부분은 com.gabdol.sw1.A 클래스가 com.gabdol.sw2 패키지 내의 클래스들을 사용하겠다는 뜻이다. 이렇게 하면 자바 컴파일러가 B b = new B(); 부분을 컴파일하면서 B라는 클래스를 com.gabdol.sw1.A가 속해있는 com.gabdol.sw1 패키지와 임포트한 com.gabdol.sw2 패키지 내에서 찾게 된다. 만일, com.gabdol.sw1과 com.gabdol.sw2 패키지에 모두 B라는 이름의 클래스가 있다면 당연히 컴파일러는 어떤 것을 써야할지 모르므로 에러를 낸다. 이 경우에는 다음처럼 하는 수밖에 없다.


package com.gabdol.sw1;
import com.gabdol.sw2.*;
...
com.gabdol.sw1.B b1 = new com.gabdol.sw1.B();
com.gabdol.sw2.B b2 = new com.gabdol.sw2.B();
...


import com.gabdol.sw1.*과 같이 *를 사용하면 com.gabdol.sw1 패키지 내의 모든 클래스를 사용하겠다는 뜻이고, com.gabdol.sw1.B 클래스만 사용한다면 import com.gabdol.sw1.B라고 명시하면 된다.


클래스패스
이제, 갑돌이는 C:\myClass\com\gabdol\sw1\A.java 파일을 컴파일하려 한다. 갑돌이는 C:\myClass\com\gabdol\sw1\ 폴더로 이동해서 다음처럼 할 것이다.

javac A.java


결과는 당연히 클래스 B를 찾을 수 없다는 에러 메시지이다. com.gabdol.sw1.B 클래스가 컴파일된 바이트코드인 B.class가 도대체 어디에 있는지 자바 컴파일러로서는 알 길이 없기 때문이다. 이 때 필요한 것이 클래스패스이다. 갑돌이가 다음처럼 하면 컴파일이 성공적으로 이루어진다.

javac -classpath C:\myClass A.java


여기에 "-classpath C:\myClass" 부분은 자바 컴파일러에게 C:\myClass폴더를 기준으로 패키지를 찾으라는 뜻이다. 즉, com.gabdol.sw1.B 클래스는 C:\myClass 폴더를 시작으로 C:\myClass\com\gabdol\sw1 폴더에서 찾고, com.gabdol.sw2.B 클래스는 C:\myClass\com\gabdol\sw2 폴더에서 찾는 것이다.

그런데, 갑돌이는 돌쇠에게 건네 받은 클래스들을 C:\otherClass 라는 폴더에 저장하고 있었는데, 이 중에 일부 클래스를 A.java에서 사용할 일이 생겼다. 돌쇠가 건네 준 클래스는 com.dolsse.ddol 이라는 패키지에 포함되어 있고, 이 클래스들은 C:\otherClass\pr\com\dolsse\ddol 폴더에 있다면, 돌쇠가 준 클래스들은 C:\otherClass\pr 폴더를 시작으로 찾아야 한다. 따라서, 돌쇠의 클래스를 사용하는 A.java 파일을 컴파일하기 위해서는 다음처럼 해야 한다.

javac -classpath "C:\myClass;C:\otherClass\pr" A.java


이렇게 하면 C:\myClass 폴더에 저장되어 있는 com.gabdol.sw1.A, com.gabdol.sw2.B 클래스와 C:\otherClass\pr 폴더에 저장되어 있는 com.dolsse.ddol.* 클래스들을 자바 컴파일러가 제대로 찾을 수 있게 되는 것이다.

A.java를 컴파일해서 얻어진 클래스를 직접 실행하려면 자바 가상 머신을 구동해야 하는데, 이 때에서 당연히 A.class가 사용하는 다른 클래스를 자바 가상 머신이 찾을 수 있어야 한다. 따라서, 역시 컴파일할 때와 마찬가지로 클래스패스가 필요하다. A.class를 실행하려면 다음처럼 해야 한다.

java -classpath "C:\myClass;C:\otherClass\pr" com.gabdol.sw1.A


실행할 때에는 실행하고자 하는 클래스의 패키지 이름까지 명시해야 한다. 왜냐하면, 자바 가상 머신이 클래스를 실행할 때에는 지정된 이름이 패키지 이름을 포함한 것으로 생각하기 때문이다. 만일, 다음처럼 한다면,

java -classpath "C:\myClass;C:\otherClass\pr" A


자바 가상 머신은 C:\myClass\A.class 혹은 C:\otherClass\pr\A.class를 찾으려고 할 것이다.

클래스패스란 여러 폴더에 산재한 클래스들의 위치를 지정해서 패키지에 따라 클래스를 제대로 찾을 수 있게 해 주는 값이다.


환경 변수
매번, 컴파일할 때와 실행할 때에 classpath 옵션에 클래스패스를 명시하는 것을 불편하다. 한 번의 설정으로 이런 문제를 해결하기 위해서 환경 변수라는 것을 사용한다. 많은 독자들이 역시 환경 변수가 무엇인지, 어떻게 설정하는지 모르는 경우가 많으므로 여기서 잘 정리해 보겠다.

환경 변수는 말 그래로 변수에 어떤 값을 저장시키되 이를 환경에 저장하는 것이다. 환경에 저장한다는 말은 그 환경 내의 모든 프로그램이 그 변수의 값을 알 수 있게 된다는 뜻이다. 여러분이 윈도우 95/98/Me의 도스창 혹은 윈도우 NT/2000의 명령창을 실행시키면, 그 명령창 내에서 각종 프로그램을 구동할 수가 있는데, 이 때, 그 명령창의 환경에 변수 값을 설정하면 그 명령창 내에서 구동되는 프로그램들은 환경 변수 값을 얻을 수가 있게 된다.

명령창 내에서 환경 변수를 설정하는 방법은 간단하다.

C:\> SET 변수이름=값


혹은

C:\> SET 변수이름="값"


처럼 하면 된다. 여러분의 명령창 또는 도스창을 띄워서 다음처럼 해 보자.

C:\> SET myname="Hong Gil Dong"


이렇게 하면 환경 변수 myname에는 "Hong Gil Dong"이 설정된다. 제대로 설정이 되었는지 확인해 보기 위해서는 다음처럼 하면 된다.

C:\> echo %myname%
"Hong Gil Dong"


첫 번째 줄은 환경 변수 myname의 값을 출력하라는 명령이고, 두 번째 줄은 그 결과가 나온 것이다.

환경 변수는 메모리가 허락하는 양만큼 설정할 수 있다. 즉, 다음처럼 복수 개의 환경 변수를 설정할 수 있다는 말이다.

C:\> SET myname="Hong Gil Dong"

C:\> SET yourname="Kim Gap Soon"


자, 이번에는 이 명령창을 종료하고 다른 명령창을 띄워 보자. 그리고, 다음처럼 myname 환경 변수의 값을 출력해 보자.

C:\> echo %myname%
%myname%


두 번째 줄과 같은 결과가 나온다. 조금 전에 설정했던 값을 온데간데 없다. 왜 그럴까? 이유는 간단하다. 환경 변수는 그 명령창 내에서만 존재하기 때문이다. myname 변수를 설정한 명령창을 종료했기 때문에, 이와 동시에 myname 환경 변수가 사라진 것이다. 또, myname 변수를 설정한 명령창을 종료하지 않았다고 해도, 다른 명령창에서는 myname 변수 값을 공유하지 않는다. 오로지, 변수를 설정한 그 명령창 내에서만 그 변수는 의미가 있게 되는 것이다.

이렇게 환경 변수가 명령창 내에서만 의미가 있기 때문에, 온갖 프로그램에서 공유하기 위해서는 명령창에서 환경 변수를 설정하는 방법 외에 다른 방법을 사용해야 한다. 윈도우 95/98/Me라면 autoexec.bat 파일을 사용하고, 윈도우 NT/2000이라면 글로벌 환경 변수를 설정하는 별도의 방법이 존재한다.

우선, 윈도우 NT/2000이라면 다음처럼 한다.

1. 바탕화면의 "내 컴퓨터"를 오른쪽 클릭한다.

2. "고급" 메뉴를 택한다.

3. 가운데 "환경 변수" 메뉴를 택한다.

4. 두 창이 나오는데 위 쪽은 특정 로그인 사용자에 대한 환경 변수를 설정하는 것이고, 아래 쪽은 모든 사용자에게 적용되는 환경 변수를 설정하는 것이다. 관리자(Administrator) 권한을 갖고 있다면 아래 시스템 변수의 값을 설정할 수 있다. 상황에 맞게 선택하면 된다.

5. 버튼이 "새로 만들기", "편집", "삭제"가 있는데, 새로운 환경 변수를 만드는 경우에는 "새로 만들기"를 클릭하고, 기존 변수 값을 수정하고자 한다면 "편집"을 누른다. "삭제"는 물론 변수를 아예 없애는 경우에 클릭한다.

6. "새로 만들기"나 "편집"을 클릭하면 변수 이름과 값을 설정하게 되어 있는데 여기에 원하는 이름과 값을 입력하면 된다.


윈도우 95/98/Me라면, autoexec.bat 파일을 편집기로 열어서 "set 변수이름=값"을 아무데나 추가하면 된다.

자, 이제는 글로벌 환경 변수에 클래스패스 변수를 설정해 보자.

윈도우 NT/2000이라면 위의 단계를 차례로 실행한 후에, 이미 CLASSPATH 혹은 classpath 변수가 있다면 이를 편집하고, 없다면 새로 만들기를 하면 된다. 지금까지 예로 든 대로라면 다음의 값을 입력하면 된다.

C:\myClass;C:\otherClass\pr

<김상욱 주: 이렇게만 하면 한 디렉토리에서 방금 만들어진 클래스파일 즉 현재 디렉토리의 클래스파일을 찾지 못하기 때문에 현재 디렉토리를 나타내는 . 을 추가한다.>

<즉, .\C:\myClass;C:\otherClass\pr 이렇게 입력하여야 합니다.>


윈도우 95/98/Me라면 autoexec.bat 파일을 열어서, 다음의 한 줄을 추가한다.

set CLASSPATH="C:\myClass;C:\otherClass\pr"

<김상욱 주: 마찬가지 이유로 set CLASSPATH=".;C:\myClass;C:\otherClass\pr" 로 입력되어야 합니다.>


그렇다면, 자바 컴파일러와 자바 가상 머신은 이렇게 설정한 환경 변수와는 어떤 관계가 있을까? 자바 컴파일러와 자바 가상 머신은 -classpath 옵션을 지정하지 않으면 환경 변수 CLASSPATH 혹은 classpath의 값을 시스템으로부터 얻어서 이를 클래스패스로 사용한다. 클래스패스의 값을 환경 변수로부터 얻을 수 있도록 애초부터 만들어진 것이다.


jar 파일과 클래스패스
jar 파일은 클래스들을 묶어 놓은 것이다. 즉, 갑돌이는 자신이 만든 com.gabdol 이하의 모든 클래스를 하나의 파일인 gabdol.jar 파일로 묶을 수가 있다. 이렇게, gabdol.jar 파일을 C:\gg\cc 폴더 아래에 두었다면 이 압축 파일 내의 클래스를 역시 자바 컴파일러와 자바 가상 머신이 찾을 수 있도록 해야 한다. 이 때에는 파일 이름까지 포함해서 클래스패스에 추가해야 한다. 다음처럼 말이다.

set CLASSPATH=C:\gg\cc\gabdol.jar;C:\myClass;C:\otherClass\pr


마치며


지금까지 자바 프로그램의 가장 기초라고 할 수 있는 클래스패스에 대해서 알아 보았다. 필자는 이 글로 더 이상의 클래스패스에 대한 질문이 사라졌으면 하는 바램이다. 독자 여러분이 클래스패스를 고민하는 것도 시간 낭비이고, 저자가 이에 대해서 일일이 답변해 주는 것도 시간 낭비라고 생각된다. 만일, 독자 여러분이 클래스를 찾지 못한다는 에러를 만난다면 100% 클래스패스 설정 잘못이므로, 이 글을 잘 읽어서 근본적으로 클래스패스에 대해서 이해한 후에 문제를 해결하는 노력을 기울이도록 하자.


신고
Posted by steloflute

http://bban2.tistory.com/185

신고
Posted by steloflute


Generate bitcoin for me

What's this?

티스토리 툴바