매크로에서 결과 파일을 저장하거나 같은 폴더의 다른 파일을 열 때, 기준이 되는 경로가 필요합니다. 코드가 들어 있는 파일이면 ThisWorkbook.Path로 끝나지만, 다른 통합 문서의 시트를 넘겨받아 처리하는 경우에는 "이 시트가 들어 있는 파일이 어디 있나"를 시트에서 거꾸로 찾아야 합니다. 여기에 더해 그 폴더의 한 단계 위 폴더가 필요한 경우도 꽤 있습니다. 예를 들어 작업\원본\data.xlsx를 처리하고 결과를 작업\결과\에 넣는 구조라면 작업 폴더를 알아야 하죠.
시트에서 통합 문서 경로 얻기
워크시트 개체의 Parent는 그 시트가 속한 Workbook입니다. 그래서 시트.Parent.Path가 통합 문서가 저장된 폴더 경로가 되고, 시트.Parent.FullName은 파일 이름까지 붙은 전체 경로입니다. 아래 코드의 objPath가 그 워크시트 변수입니다.
'특정 시트의 워크북 상위폴더
Dim fPath As String
fPath = StrReverse(objPath.Parent.Path) '// 해당 시트의 파일경로값을 좌우로 뒤집어 넣음
fPath = StrReverse(Right(fPath, Len(fPath) - InStr(fPath, "\\"))) '// 상위 폴더
코드가 들어 있는 파일 기준이라면 ThisWorkbook을 바로 씁니다.
'ThisWorkbook 의 상위폴더
Dim fPath As String
fPath = StrReverse(ThisWorkbook.Path) '// 파일경로값을 좌우로 뒤집어 넣음
fPath = StrReverse(Right(fPath, Len(fPath) - InStr(fPath, "\"))) '// 상위 폴더
경로를 뒤집어서 자르는 이유
VBA의 InStr은 앞에서부터 찾기 때문에, 경로의 마지막 역슬래시 위치를 바로 구할 수 없습니다. 그래서 StrReverse로 경로를 거꾸로 뒤집으면 마지막 역슬래시가 맨 앞쪽으로 오고, InStr로 그 위치를 찾은 뒤 Right로 그 뒤쪽만 남깁니다. 이걸 다시 뒤집으면 마지막 폴더 이름이 잘려 나간 상위 경로가 됩니다.
예를 들어 경로가 C:\작업\원본이면 뒤집어서 본원\업작\:C가 되고, 첫 역슬래시까지(본원\)를 버린 업작\:C를 다시 뒤집으면 C:\작업이 남습니다.
주의: 첫 번째 코드의 "\"
첫 번째 코드에서는 InStr(fPath, "\\")로 역슬래시를 두 개 찾고 있습니다. VBA 문자열은 역슬래시를 이스케이프하지 않으니 이건 말 그대로 \\ 두 글자를 찾는 것이고, 일반 경로에는 그런 부분이 없어서 InStr이 0을 돌려줍니다. 그러면 Right(fPath, Len(fPath))가 되어 상위 폴더가 아니라 원래 경로가 그대로 나옵니다. 두 번째 코드처럼 "\" 하나로 바꿔야 의도대로 동작합니다.
fPath = StrReverse(Right(fPath, Len(fPath) - InStr(fPath, "\")))
다른 방법과 조심할 점
VBA6 이후라면 뒤에서부터 찾는 InStrRev가 있어서 뒤집지 않고도 같은 결과를 낼 수 있습니다. Left(경로, InStrRev(경로, "\") - 1) 한 줄이면 됩니다. FileSystemObject의 GetParentFolderName을 쓰는 방법도 있고요.
어느 방식이든 한 번도 저장하지 않은 새 통합 문서는 Path가 빈 문자열이라 이 코드가 엉뚱하게 동작합니다. 그리고 C:\data처럼 드라이브 바로 아래 폴더라면 결과가 C:가 되어 끝에 역슬래시가 없으니, 뒤에 파일 이름을 붙일 때 "\"를 빠뜨리지 않도록 확인해야 합니다. OneDrive에 동기화된 파일은 Path가 https://로 시작하는 URL로 나오는 경우가 있어서, 이때는 역슬래시가 아니라 슬래시로 나뉜다는 점도 알아 두면 좋습니다.