본문 바로가기
ABAP 문법 & 기법

[SAP ABAP] 파일 업/다운로드 경로 자동 저장·복원 — file_open_dialog initial_directory + SPA/GPA 메모리 ID

by Song.sh 2026. 5. 22.

SAP 리포트에서 사용자가 PC 파일을 업로드 / 다운로드하는 화면을 만들 때, 첫 호출 시에는 사용자가 매번 C 드라이브 최상위부터 폴더를 헤매고, 같은 화면을 다시 열어도 또 처음부터 경로를 찾아 들어가야 합니다. 사용자 경험이 나쁘고 업무 시간도 낭비됩니다.

 

표준 SAP 에서 이 문제를 해결하는 방법은 이전에 사용한 경로를 어딘가에 저장해 두었다가 다음 호출 시 initial_directory 파라미터로 넘겨주는 것 입니다. 저장 위치는 두 가지 — SPA/GPA 메모리 ID(세션 단위 임시)Z 테이블(사용자별 영구 저장). 시나리오에 따라 선택해서 사용합니다.

 

이 글에서는 두 방법의 구현 패턴 · 장단점 · 메모리 ID 작명 규칙 · Z 테이블 구조 · 파일 다이얼로그 표준 API(file_open_dialog · file_save_dialog) 와의 연동 · 함정까지 한 번에 정리합니다.

핵심 — 두 가지 저장 방식 비교

항목 방법1 — SPA/GPA 메모리 ID 방법2 — Z 테이블 영구 저장
저장 위치 SAP 사용자 세션 메모리 DB 테이블 (Z 자체)
지속 시간 세션 동안 (로그아웃 시 초기화) 영구 (다음 날도 유지)
구현 비용 매우 낮음 (2줄) 중간 (테이블 + SELECT/MODIFY)
사용자 PC 변경 즉시 반영 (세션 단위) 즉시 반영 (DB 단위)
운영 부담 없음 (메모리 자동) CTS 이송 · 사용자 데이터 백업

선택 기준 — 하루 동안만 유지되면 충분 하면 방법1, 다음 날 / 다음 주에도 유지되어야 하면 방법2. 두 방식을 결합한 하이브리드 (Z 테이블에서 가져온 후 메모리에도 함께 저장) 도 가능합니다.


1단계 — 방법1: SPA/GPA 메모리 ID 활용

가장 가벼운 방법. SET PARAMETER ID / GET PARAMETER ID 두 줄로 끝.

DATA: lv_path     TYPE string,
      lt_file     TYPE filetable,
      lv_rc       TYPE i,
      lv_action   TYPE i.

" ★ 1) 메모리 ID 에서 이전 사용 경로 가져오기
GET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_path.

" 2) 파일 다이얼로그 호출 (이전 경로를 기본값으로)
cl_gui_frontend_services=>file_open_dialog(
  EXPORTING
    window_title       = '파일 선택'
    initial_directory  = lv_path           " ★ 핵심 — 이전 경로 전달
    multiselection     = abap_false
  CHANGING
    file_table         = lt_file
    rc                 = lv_rc
    user_action        = lv_action
  EXCEPTIONS
    OTHERS             = 1 ).

CHECK lv_action = cl_gui_frontend_services=>action_ok.

" 3) 선택 결과 처리
READ TABLE lt_file INTO DATA(ls_file) INDEX 1.
DATA(lv_full_path) = CONV string( ls_file-filename ).

" ★ 4) 디렉토리 부분만 추출해서 메모리에 저장
DATA lv_dir TYPE string.
FIND REGEX '^(.*)[/\\][^/\\]+$' IN lv_full_path SUBMATCHES lv_dir.

IF sy-subrc = 0.
  SET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_dir.
ENDIF.

메모리 ID 작명 — Z 접두사 + 의미 있는 이름. SU01 사용자 마스터의 Parameters 탭에 해당 메모리 ID 가 미리 등록되어 있을 필요는 없습니다 (자동 생성).

SET PARAMETER 의 길이 제한 — SPA/GPA 는 기본 132자. 일반적인 PC 경로는 충분하지만 매우 깊은 디렉토리 구조에서는 잘릴 수 있어 사전 길이 체크 권장.


2단계 — 방법2: Z 테이블 영구 저장

여러 날 / 여러 세션에 걸쳐 경로를 유지하려면 자체 테이블 활용.

Z 테이블 정의 — ZTXX_FILE_PATH (예시)

+----------+-----------+--------+---------+
| Field    | DataType  | Length | Key     |
+----------+-----------+--------+---------+
| MANDT    | CLNT      |   3    | Yes     |
| UNAME    | SYUNAME   |  12    | Yes     |
| PROGRAM  | SYREPID   |  40    | Yes     |
| TYPE     | CHAR1     |   1    | Yes     |  ← U(Upload) / D(Download)
| PATH     | STRING    |   -    | No      |
| AEDAT    | DATUM     |   8    | No      |
+----------+-----------+--------+---------+

키 — 사용자(UNAME) + 프로그램(PROGRAM) + 유형(TYPE) 조합. 같은 사용자라도 업로드 / 다운로드 / 다른 프로그램별로 경로를 따로 유지할 수 있습니다.

조회 + 다이얼로그 + 저장 흐름:

DATA: lv_path TYPE string,
      lt_file TYPE filetable,
      lv_rc   TYPE i.

" ★ 1) Z 테이블에서 이전 경로 조회
SELECT SINGLE path
  INTO @lv_path
  FROM ztxx_file_path
 WHERE uname   = @sy-uname
   AND program = @sy-repid
   AND type    = 'U'.            " Upload

" 2) 파일 다이얼로그 호출
cl_gui_frontend_services=>file_open_dialog(
  EXPORTING
    window_title      = '파일 선택'
    initial_directory = lv_path
  CHANGING
    file_table        = lt_file
    rc                = lv_rc
    user_action       = DATA(lv_action) ).

CHECK lv_action = cl_gui_frontend_services=>action_ok.

" 3) 선택 결과
READ TABLE lt_file INTO DATA(ls_file) INDEX 1.
DATA(lv_full_path) = CONV string( ls_file-filename ).

DATA lv_dir TYPE string.
FIND REGEX '^(.*)[/\\][^/\\]+$' IN lv_full_path SUBMATCHES lv_dir.

" ★ 4) Z 테이블에 새 경로 영구 저장
IF sy-subrc = 0.
  MODIFY ztxx_file_path FROM @( VALUE #(
    mandt   = sy-mandt
    uname   = sy-uname
    program = sy-repid
    type    = 'U'
    path    = lv_dir
    aedat   = sy-datum ) ).
ENDIF.

3단계 — 다운로드 시 file_save_dialog

다운로드 화면도 동일한 패턴. file_save_dialoginitial_directory 파라미터를 받습니다.

DATA: lv_path     TYPE string,
      lv_filename TYPE string,
      lv_action   TYPE i.

GET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_path.

cl_gui_frontend_services=>file_save_dialog(
  EXPORTING
    window_title         = '저장 위치 선택'
    default_extension    = 'xlsx'
    default_file_name    = 'export'
    initial_directory    = lv_path                " ★
    file_filter          = 'Excel Files (*.xlsx)|*.xlsx|'
  CHANGING
    filename             = lv_filename
    path                 = lv_path
    fullpath             = DATA(lv_fullpath)
    user_action          = lv_action
  EXCEPTIONS
    OTHERS               = 1 ).

CHECK lv_action = cl_gui_frontend_services=>action_ok.

" 실제 다운로드 (예: GUI_DOWNLOAD)
cl_gui_frontend_services=>gui_download(
  EXPORTING
    filename = lv_fullpath
    filetype = 'BIN'
  CHANGING
    data_tab = lt_binary_data
  EXCEPTIONS
    OTHERS   = 1 ).

" 새 경로 저장
SET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_path.

업로드용 메모리 ID 와 다운로드용 메모리 ID 를 분리 하는 것이 중요. 사용자가 일반적으로 업로드는 Downloads 폴더에서, 다운로드는 Documents 폴더에 저장하는 식으로 다르기 때문에 한 ID 로 두면 매번 잘못된 폴더에서 시작합니다.


4단계 — 하이브리드 패턴 (Z 테이블 + 메모리 ID)

가장 사용자 경험이 좋은 방식. 세션 안에서는 메모리 ID 로 빠르게 가져오고, 세션 시작 시점에는 Z 테이블 에서 영구 저장된 값을 로드.

DATA lv_path TYPE string.

" ★ 1) 메모리 먼저 확인
GET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_path.

" 메모리에 없으면 Z 테이블에서 가져옴
IF lv_path IS INITIAL.
  SELECT SINGLE path
    INTO @lv_path
    FROM ztxx_file_path
   WHERE uname   = @sy-uname
     AND program = @sy-repid
     AND type    = 'U'.

  IF lv_path IS NOT INITIAL.
    " 메모리에 캐시
    SET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_path.
  ENDIF.
ENDIF.

" 2) file_open_dialog 호출
" ... ( 기존 패턴 ) ...

" ★ 3) 선택 후 메모리 + Z 테이블 둘 다 저장
SET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_dir.

MODIFY ztxx_file_path FROM @( VALUE #(
  mandt   = sy-mandt
  uname   = sy-uname
  program = sy-repid
  type    = 'U'
  path    = lv_dir
  aedat   = sy-datum ) ).

장점 — 세션 안에서는 DB 호출 없이 빠르게 동작하고, 세션 시작 / 다음 날 로그인 시점에는 영구 저장된 경로가 자동 복원됩니다.


5단계 — 디렉토리만 선택할 때 (directory_browse)

파일이 아니라 폴더만 선택할 때는 directory_browse. 다중 파일 일괄 처리 / ZIP 다운로드 등에 사용.

DATA: lv_folder TYPE string.

GET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_folder.

cl_gui_frontend_services=>directory_browse(
  EXPORTING
    window_title         = '폴더 선택'
    initial_folder       = lv_folder            " ★
  CHANGING
    selected_folder      = lv_folder
  EXCEPTIONS
    OTHERS               = 1 ).

CHECK sy-subrc = 0.

" 메모리 갱신
SET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_folder.

initial_folderselected_folder 가 같은 변수를 가리키므로 사용자가 변경한 경로가 그대로 갱신됩니다.


흔히 빠뜨리는 함정

디렉토리 / 파일명 분리 실패

file_open_dialog 가 돌려주는 filename풀 경로 + 파일명 형태(C:\Users\Alice\report.xlsx). 디렉토리만 저장하려면 마지막 슬래시 이전까지만 잘라야 합니다. 풀 경로를 그대로 저장하면 다음 호출 시 파일명이 폴더로 인식되어 다이얼로그가 이상하게 뜹니다.

메모리 ID 길이 132자 제한

SPA/GPA 의 길이가 132자로 잘립니다. 매우 깊은 폴더 구조에서는 잘려서 잘못된 경로가 됩니다. 운영 전 사용자 디렉토리 깊이를 확인하고, 가능성이 있다면 Z 테이블(STRING 타입) 사용.

슬래시 / 백슬래시 혼합

Windows 는 \, 일부 라이브러리는 / 를 사용합니다. 경로 매칭 / 합치기 시 둘 다 처리하는 정규식이 안전 — [/\\] 패턴 활용.

메모리 ID 충돌

같은 시스템에 다른 프로그램에서 같은 ID 를 쓰면 경로가 섞입니다. 메모리 ID 는 프로그램 단위 / 시나리오 단위로 고유 하게 — 예: ZUPLOAD_PO·ZUPLOAD_INV 같이 의미를 붙임.

Z 테이블 권한

자체 테이블에 사용자별 데이터가 쌓이므로 SE16N 의 일반 권한이 있는 사용자가 다른 사용자의 경로를 볼 수 있습니다. 권한 그룹(DELIVERY · DICBERCLS) 을 적용해서 노출 범위 제한.

사용자 PC 마이그레이션

사용자가 PC 를 교체했는데 Z 테이블에 옛 PC 의 경로가 남아 있으면, 새 PC 에서 그 경로가 없어 다이얼로그가 빈 상태로 뜨거나 에러가 발생할 수 있습니다. cl_gui_frontend_services=>directory_exist 로 존재 여부 사전 체크 후 없으면 기본값으로 fallback.

Linux / Mac SAP GUI 사용자

드물지만 Mac / Linux 의 SAP GUI 사용자는 경로 형식이 다릅니다(/Users/Alice/). 멀티 플랫폼 회사라면 OS 분기 필요 — cl_gui_frontend_services=>get_platform( ).

첫 호출 시 빈 경로

첫 호출에서는 메모리 / Z 테이블 모두 빈 값. initial_directory = '' 를 그대로 넘기면 다이얼로그가 기본 폴더로 뜨는데, 회사 정책상 특정 기본 폴더(C:\Users\<사용자>\Downloads) 로 유도하려면 첫 호출 시 fallback 처리.


전체 코드 — 복사용 통합본 (하이브리드 패턴)

*&---------------------------------------------------------------------*
*& Report  Z_XX_FILE_PATH_MEMORY
*&---------------------------------------------------------------------*
*& 업/다운로드 경로 자동 저장 + 재사용 (하이브리드)
*&---------------------------------------------------------------------*
REPORT z_xx_file_path_memory.

PARAMETERS: p_type TYPE c LENGTH 1 DEFAULT 'U'.   " U=Upload · D=Download

START-OF-SELECTION.
  IF p_type = 'U'.
    PERFORM upload_file.
  ELSE.
    PERFORM download_file.
  ENDIF.

*---------------------------------------------------------------------*
*  Form upload_file
*---------------------------------------------------------------------*
FORM upload_file.

  DATA: lv_path     TYPE string,
        lv_dir      TYPE string,
        lt_file     TYPE filetable,
        lv_rc       TYPE i,
        lv_action   TYPE i.

  " ★ 1) 메모리 → Z 테이블 순으로 이전 경로 조회
  GET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_path.

  IF lv_path IS INITIAL.
    SELECT SINGLE path
      INTO @lv_path
      FROM ztxx_file_path
     WHERE uname   = @sy-uname
       AND program = @sy-repid
       AND type    = 'U'.

    IF lv_path IS NOT INITIAL.
      SET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_path.
    ENDIF.
  ENDIF.

  " 2) 다이얼로그 호출
  cl_gui_frontend_services=>file_open_dialog(
    EXPORTING
      window_title      = '업로드 파일 선택'
      initial_directory = lv_path
      multiselection    = abap_false
    CHANGING
      file_table        = lt_file
      rc                = lv_rc
      user_action       = lv_action
    EXCEPTIONS
      OTHERS            = 1 ).

  CHECK lv_action = cl_gui_frontend_services=>action_ok.

  " 3) 디렉토리 부분만 추출
  READ TABLE lt_file INTO DATA(ls_file) INDEX 1.
  FIND REGEX '^(.*)[/\\][^/\\]+$' IN ls_file-filename SUBMATCHES lv_dir.

  CHECK sy-subrc = 0.

  " ★ 4) 메모리 + Z 테이블 둘 다 저장
  SET PARAMETER ID 'ZUPLOAD_PATH' FIELD lv_dir.

  MODIFY ztxx_file_path FROM @( VALUE #(
    mandt   = sy-mandt
    uname   = sy-uname
    program = sy-repid
    type    = 'U'
    path    = lv_dir
    aedat   = sy-datum ) ).

  " 5) 실제 업로드 처리
  WRITE: / '선택된 파일:', ls_file-filename.
  WRITE: / '저장된 경로:', lv_dir.

ENDFORM.

*---------------------------------------------------------------------*
*  Form download_file
*---------------------------------------------------------------------*
FORM download_file.

  DATA: lv_path     TYPE string,
        lv_filename TYPE string,
        lv_fullpath TYPE string,
        lv_action   TYPE i.

  " ★ 1) 다운로드용 메모리 / Z 테이블 조회
  GET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_path.

  IF lv_path IS INITIAL.
    SELECT SINGLE path
      INTO @lv_path
      FROM ztxx_file_path
     WHERE uname   = @sy-uname
       AND program = @sy-repid
       AND type    = 'D'.

    IF lv_path IS NOT INITIAL.
      SET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_path.
    ENDIF.
  ENDIF.

  " 2) 저장 다이얼로그
  cl_gui_frontend_services=>file_save_dialog(
    EXPORTING
      window_title         = '저장 위치 선택'
      default_extension    = 'xlsx'
      default_file_name    = 'report'
      initial_directory    = lv_path
      file_filter          = 'Excel Files (*.xlsx)|*.xlsx|'
    CHANGING
      filename             = lv_filename
      path                 = lv_path
      fullpath             = lv_fullpath
      user_action          = lv_action
    EXCEPTIONS
      OTHERS               = 1 ).

  CHECK lv_action = cl_gui_frontend_services=>action_ok.

  " ★ 3) 새 경로 저장
  SET PARAMETER ID 'ZDOWNLOAD_PATH' FIELD lv_path.

  MODIFY ztxx_file_path FROM @( VALUE #(
    mandt   = sy-mandt
    uname   = sy-uname
    program = sy-repid
    type    = 'D'
    path    = lv_path
    aedat   = sy-datum ) ).

  " 4) 실제 다운로드 처리 (예: GUI_DOWNLOAD)
  WRITE: / '저장 경로:', lv_fullpath.

ENDFORM.

같이 보면 좋은 글:

  • "CL_GOS_MANAGER 첨부파일 활용 — 자체 화면에 표준 GOS 서비스 끼우기" — 표준 첨부 메뉴와 함께 사용
  • "SWU_OBJECT_PUBLISH ALV GOS 아이콘 만드는 방법" — ALV 리포트의 첨부 흐름과 연동
  • "BAPI · BDC 에러 메시지 확인 방법 — MESSAGE INTO · FORMAT_MESSAGE 빌드" — 업로드 실패 / 권한 부족 시 메시지 처리

요약

단계 하는 일 핵심 포인트
1 이전 경로 조회 GET PARAMETER ID / SELECT ZT*
2 다이얼로그 호출 initial_directory 파라미터에 전달
3 디렉토리 추출 정규식 ^(.*)[/\\\\][^/\\\\]+$
4 경로 저장 SET PARAMETER ID + MODIFY ZT*
5 업/다운 분리 메모리 ID + Z 테이블 키 별도 운영

업/다운로드 경로 자동 저장은 SPA/GPA 메모리 ID 와 Z 테이블 두 도구의 조합 으로 깔끔하게 처리됩니다. 세션 안에서는 메모리로 빠르게, 다음 로그인 / 다음 날에는 Z 테이블에서 영구 복원. 업로드용 / 다운로드용 메모리 ID 와 테이블 키를 분리하고, 첫 호출 시 빈 경로 fallback, 정규식으로 디렉토리만 깔끔하게 추출하는 패턴을 표준으로 잡아두면 사용자 경험과 운영 안정성을 동시에 잡을 수 있습니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

cl_gui_frontend_services 메소드 시그니처 · SET / GET PARAMETER ID 동작은 SAP NetWeaver 표준(ECC 6.0 / S/4HANA on-premise) 기준이며, 사내 보안 / 클라이언트 OS · 권한 그룹 정책에 따라 일부 동작이 다를 수 있으니 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다. Z 테이블 설계 시 사용자별 권한 / GDPR · 개인정보 정책에 따른 보관 기간도 함께 검토하시기 바랍니다.