디렉토리(directory) 접근 C++ Win32 함수 총정리

프로그래밍/c++ 2013.02.12 14:56

파일 열기(읽기), 파일 저장(쓰기/생성), 디렉토리(폴더) 열기(읽기), 현재 경로(path) 변경 등 파일 시스템에 접근하기 위한 win32 함수 사용법들을 정리해 봤습니다. win32 버전 함수들을 알아두면 굳이 mfc 함수를 사용하지 않아도 되기 때문에 여러모로 좋습니다 (포스트 말미에 텍스트 코드를 첨부합니다).




1. 현재 경로(path) 알아내기 및 변경하기

2. 파일 읽기/열기(file read/open) 경로(path) 얻기

3. 파일 저장(write/save/create) 경로 얻기

4. 폴더 경로명 얻기 (folder open)

5. 현재 경로를 루트(root)로 폴더 선택하기 (Unicode encoding)

6. 현재 경로를 루트(root)로 폴더 선택하기 (Multi-Byte or No encoding)

7. 현재 폴더(디렉토리)의 파일 목록(리스트) 접근하기

8. 경로 분해하기

9. 현재 날짜, 시간을 파일명에 덧붙이기

10. 상위 디렉토리(폴더)로 이동하기

11. 코드 다운로드


1. 현재 경로(path) 알아내기 및 변경하기

TCHAR sPath[MAX_PATH] = {0,};

::GetCurrentDirectory(MAX_PATH, sPath);

::SetCurrentDirectory(_T("c:\\"));


2. 파일 읽기/열기(file read/open) 경로(path) 얻기

파일 열기 대화상자 사용법입니다. 아래 예제에서는 avi 파일을 열도록 필터를 설정했습니다. 필터 없이 모든 파일을 보여주려면 lpstrFilter에 NULL을 주면 됩니다.

TCHAR szFilePath[MAX_PATH] = {0,};

OPENFILENAME ofn;

ZeroMemory(&ofn, sizeof(OPENFILENAME));

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = NULL;

ofn.lpstrFile = szFilePath;

ofn.nMaxFile = sizeof(szFilePath);

ofn.lpstrFilter = _T("Avi Files(*.avi)\0*.avi\0All Files (*.*)\0*.*\0");

ofn.nFilterIndex = 1;

ofn.lpstrFileTitle = NULL;

ofn.nMaxFileTitle = 0;

ofn.lpstrInitialDir = NULL;

ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if(::GetOpenFileName(&ofn)==false) return;


TCHAR *return_path = ofn.lpstrFile;


3. 파일 저장(write/save/create) 경로 얻기

파일 저장 대화상자 사용법입니다. 아래 예와 같이 필터(*.avi)를 사용한다고 해서 자동으로 avi가 확장자로 붙는건 아닙니다. 사용자가 입력한 경로명을 보고 필요한 경우 프로그래머가 직접 확장자를 추가해 주어야 합니다. 필터를 해제하려면 lpstrFilter에 NULL을 주면 됩니다.

TCHAR szFile[260] = _T("");

OPENFILENAME ofn;

ZeroMemory(&ofn, sizeof(OPENFILENAME));

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = NULL;

ofn.lpstrFile = szFile;

ofn.nMaxFile = sizeof(szFile);

ofn.lpstrFilter = _T("Avi Files(*.avi)\0*.avi\0All Files (*.*)\0*.*\0");

ofn.nFilterIndex = 1;

ofn.lpstrFileTitle = NULL;

ofn.nMaxFileTitle = 0;

ofn.lpstrInitialDir = NULL;

ofn.Flags = OFN_OVERWRITEPROMPT;

if(::GetSaveFileName(&ofn)==false) return;


TCHAR *return_path = ofn.lpstrFile;


4. 폴더 경로명 얻기 (folder open)

파일이 아닌 폴더(디렉토리)를 열고자 할 때는 다음과 같이 합니다.

TCHAR cpath[MAX_PATH] = _T("");

LPITEMIDLIST pDirList;

BROWSEINFO browseInfo;

browseInfo.hwndOwner = NULL;

browseInfo.pidlRoot = NULL;

browseInfo.lpszTitle = _T("이미지들을 불러올 폴더를 선택해 주세요");

browseInfo.pszDisplayName = cpath;

browseInfo.ulFlags = BIF_RETURNONLYFSDIRS;

browseInfo.lpfn = NULL;

browseInfo.lParam = 0;

pDirList = SHBrowseForFolder(&browseInfo);

if(pDirList == NULL) return;

SHGetPathFromIDList(pDirList, cpath);


TCHAR *return_path = cpath;


5. 현재 경로를 루트(root)로 폴더 선택하기 (Unicode encoding)

현재 프로그램이 실행되는 폴더/경로를 루트로 폴더 열기 대화상자를 생성합니다 (Unicode 인코딩을 사용할 경우).

// set current directory to be root directory

TCHAR sPath[MAX_PATH] = {0};

::GetCurrentDirectory(MAX_PATH, sPath);


LPITEMIDLIST pStartDir;

ULONG nCharsParsed = 0;

LPSHELLFOLDER pShellFolder = NULL;

SHGetDesktopFolder(&pShellFolder);

HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, sPath, &nCharsParsed, &pStartDir, NULL);

pShellFolder->Release();


// Get directory from user

TCHAR cpath[MAX_PATH];

LPITEMIDLIST pDirList;

BROWSEINFO browseInfo;

browseInfo.hwndOwner = NULL; // m_hWnd

browseInfo.pidlRoot = pStartDir;

browseInfo.lpszTitle = _T("이미지들을불러올폴더를선택해주세요");

browseInfo.pszDisplayName = cpath;

browseInfo.ulFlags = BIF_RETURNONLYFSDIRS;

browseInfo.lpfn = NULL;

browseInfo.lParam = 0;

pDirList = SHBrowseForFolder(&browseInfo);

if(pDirList == NULL) return;

SHGetPathFromIDList(pDirList, cpath);


TCHAR *return_path = cpath;


6. 현재 경로를 루트(root)로 폴더 선택하기 (Multi-Byte or No encoding)

현재 프로그램이 실행되는 폴더/경로를 루트로 폴더 열기 대화상자를 생성합니다 (Multi-byte 인코딩을 사용할 경우 또는 인코딩을 설정하지 않았을 경우).

// set current directory to be root directory

TCHAR sPath[MAX_PATH] = {0};

::GetCurrentDirectory(MAX_PATH, sPath);

OLECHAR wszPath[MAX_PATH] = {0};

MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)sPath, -1, wszPath, MAX_PATH);


LPITEMIDLIST pStartDir;

ULONG nCharsParsed = 0;

LPSHELLFOLDER pShellFolder = NULL;

SHGetDesktopFolder(&pShellFolder);

HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, &pStartDir, NULL);

pShellFolder->Release();


// Get directory from user

TCHAR cpath[MAX_PATH];

LPITEMIDLIST pDirList;

BROWSEINFO browseInfo;

browseInfo.hwndOwner = NULL; // m_hWnd

browseInfo.pidlRoot = pStartDir;

browseInfo.lpszTitle = _T("이미지들을불러올폴더를선택해주세요");

browseInfo.pszDisplayName = cpath;

browseInfo.ulFlags = BIF_RETURNONLYFSDIRS;

browseInfo.lpfn = NULL;

browseInfo.lParam = 0;

pDirList = SHBrowseForFolder(&browseInfo);

if(pDirList == NULL) return;

SHGetPathFromIDList(pDirList, cpath);


TCHAR *return_path = cpath;


7. 현재 폴더(디렉토리)의 파일 목록(리스트) 접근하기

아래 예는 현재 경로의 폴더에 있는 모든 txt 파일의 파일이름을 출력하는 예입니다. 모든 파일을 접근하고 싶으면 _findfirst(“*.*”,&c_file)와 같이 하면 됩니다.

      struct _finddata_t c_file;

      intptr_t hFile = _findfirst("*.txt", &c_file);

      if(hFile==-1) return;      // no files

      do

      {

            if(c_file.attrib & _A_SUBDIR)

            {

                  // directory 처리

            }

            else if(c_file.attrib & _A_HIDDEN)

            {

                  // hidden file 처리

            }

            else

            {

                  // 일반 파일 처리

                  printf("%s\n", c_file.name);

            }

      } while(_findnext(hFile, &c_file)==0);

      _findclose(hFile);


8. 경로 분해하기

파일 경로를 드라이브, 디렉토리, 파일명, 확장자로 분리하는 함수입니다.

char fdrive[5];

char fdir[200];

char fname[100];

char fext[10];

_splitpath_s(path, fdrive, 5, fdir, 200, fname, 100, fext, 10);


9. 현재 날짜, 시간을 파일명에 덧붙이기

반복적으로 파일을 저장해야 하는 경우 현재 시간을 파일명에 덧붙이면 나중에 참조할 때 편리하기도 하고 또한 기존 파일을 실수로 덮어쓰는 것을 방지할 수 있습니다.

char save_path[MAX_PATH];

SYSTEMTIME st;

GetLocalTime(&st);

sprintf_s(save_path, MAX_PATH, "filepath_%d.%d.%d_%d.%d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);


10. 상위 디렉토리(폴더)로 이동하기

현재 경로의 parent directory로 이동하기 위한 방법입니다.

TCHAR path[MAX_PATH] = {0,};

::GetCurrentDirectory(MAX_PATH, path);


int i = _tcslen(path) - 1;

while(i>=0 && path[i]!='\\') i--;

if(i<=0) return;

path[i] = 0;

::SetCurrentDirectory((LPCTSTR)path);



11. 코드 다운로드

DirAccess.txt


by 다크 프로그래머

  • 심심이 2014.10.25 17:55 신고 ADDR 수정/삭제 답글

    안녕하세요 c++ 공부하다가 들립니다.
    한가지 여쭤보고 싶은데 10번의 상위 디렉토리 이동에서 한단계 더 상위로 가려면 어떻게 해야되는지 알고 싶습니다.

    • BlogIcon 다크pgmr 2014.10.25 19:09 신고 수정/삭제

      아래와 같이 i를 1 감소시킨후 while문을 한번 더 적용하면 되리라 생각합니다.
      TCHAR path[MAX_PATH] = {0,};
      ::GetCurrentDirectory(MAX_PATH, path);

      int i = _tcslen(path) - 1;
      while(i>=0 && path[i]!='\\') i--;
      i--;
      while(i>=0 && path[i]!='\\') i--;
      if(i<=0) return;
      path[i] = 0;
      ::SetCurrentDirectory((LPCTSTR)path);

  • BlogIcon 유호균 2015.06.07 15:30 신고 ADDR 수정/삭제 답글

    저 위에 있는 그림대로 하는 소스는 따로 없는건가요 ㅜㅜ 이제 처음 공부를 하려고하는데 소스랑 변수 같은것들을 보면서 하고싶어서 그런데 소스좀 보내주실수있으신가요? ㅜ
    1030ghrbs@naver.com 입니다 ㅜ

    • BlogIcon 다크pgmr 2015.06.08 10:26 신고 수정/삭제

      구체적인 프로그래밍에 대해서는 관련 서적을 보시는게 더 좋을 것 같습니다..

  • 얼랄라 2016.07.27 16:17 신고 ADDR 수정/삭제 답글

    안녕하세요. 항상 좋은 정보 잘 보고 있습니다.

    제가 하고 싶은 부분은 폴더를 선택하여 path를 얻고 그 안의 모든 파일들을 차례로 불러오는 것입니다. 열심히 검색하여보니 예를 들어,

    std::vector<cv::String> files;
    cv::String path_input("/Datasets");

    cv::glob(path_input + "/*.png", files);

    와 같이 glob 함수를 이용하면 비교적 간단하게 불러올 수 있다고 합니다. 헌데, 이 코드가 visual studio 2015 환경에서 사용하면, glob 함수에서 엑세스 위반이 발생합니다. 세번째 recursive 인자로 false, true 다 시도 해보았지만 마찬가지 결과입니다. (path는 잘 받아오는 것까지 확인되어 집니다.) 2012 환경에서는 사용 가능한 것으로 확인되었는데, 혹시 해당 내용에 대해 해결 방안을 알고 계시다면 조언 부탁드립니다. 감사합니다.

    • 얼랄라 2016.07.27 17:14 신고 수정/삭제

      혹시 visual studio 2015를 opencv249에서 지원하지 못하는 이유일까요..

    • BlogIcon 다크pgmr 2016.07.27 22:39 신고 수정/삭제

      저는 glob 함수는 써보지 않아서 잘 모릅니다만, 본문의 7번 예제와 같이 _findfirst, _findnext 함수로는 디렉토리 파일 검색이 잘 안되나요?

    • 얼랄라 2016.07.28 09:40 신고 수정/삭제

      답변 감사드립니다. 시도해보겠습니다. 헌데, 현재의 경로 말고 원하는 절대 경로의 위치를 지정할 수 있을까요?

    • BlogIcon 다크pgmr 2016.07.28 09:50 신고 수정/삭제

      글쎄요.. 절대경로에 대해서도 동작하는지는 잘 모르겠네요. 하지만 우회적인 방법으로 SetCurrentDirectory()함수를 이용하여 원하는 경로로 이동한 후 파일 검색을 하면 됩니다. 작업을 마친 후 원래 경로로 돌아오고자 할 경우에는 이동하기 전에 GetCurrentDirectory로 현재 경로를 얻어서 따로 저장해 놓으면 될 것입니다.

    • 얼랄라 2016.07.28 10:45 신고 수정/삭제

      감사합니다. 도움이 많이 되었습니다!