C++/MFC

[MFC] 파일 및 폴더 검색기

balabala 2021. 8. 23. 20:17
728x90
SMALL
- 설명 - 
프로젝트 명 : SearchFile(대화 상자 기반)
① 파일 및 폴더의 문자열을 비교하여 검색
② 하단 리스트 박스에 조건에 부합하는 파일 및 폴더의 정보가 나타남
③ 리스트 박스 아래 현재 검색 중인 폴더 이름이 나타남
④ "하위 폴더 검색" 체크 시 하위 폴더 검색 진행

 

1. 다이얼로그 디자인 및 ID

그림1. 메인 다이얼로그

 

2. CSearchFileDlg 클래스 멤버 변수 목록
사용자 지정 변수
BOOL m_bStop : 검색 도중 중단 버튼 역활
CString m_strToken : 검색 시 활용할 문자열 조건
CImageList m_img : 아이콘

그림2. CSearchFileDlg 클래스 멤버변수

 

3. 클래스 마법사를 이용하여 클래스 추가
CFileFindEx : 파일 정보를 CString 형으로 변환
CListCtrlEx : 리스트 컨트롤에 아이콘 삽입 가능하게 변환

그림3. 클래스 추가 방법
그림4. CFileFindEx 클래스 추가
그림5. CListCtrlEx 클래스 추가

4. CFileFindEx 클래스 멤버 정의
GetLengthString : 파일의 크기를 CString형으로 넘겨줌
GetCreationTimeString : 파일 생성 시간을 CString형으로 넘겨줌
  • FileFindEx.h 소스 보기
더보기
#pragma once
#include <afx.h>
class CFileFindEx :
    public CFileFind
{
public:
    CFileFindEx(void);
    ~CFileFindEx(void);
    CString GetLengthString();                           // 파일의 크기를 스트링으로 넘겨줌
    CString GetCreationTimeString(CString strTmp = "-"); // 파일 생성 시간을 스트링으로 넘겨줌
};
 
  • FileFindEx.cpp 소스 보기
더보기
#include "pch.h"
#include "FileFindEx.h"

CFileFindEx::CFileFindEx(void) {
}
CFileFindEx::~CFileFindEx(void) {
}

CString CFileFindEx::GetCreationTimeString(CString strTmp) {
    CString str;
    CTime cTime;

    GetCreationTime(cTime);

    str.Format("%02d%s%02d%s%02d %02d:%02d", cTime.GetYear(), strTmp, cTime.GetMonth(), strTmp, cTime.GetDay(), cTime.GetHour(), cTime.GetDay());

    return str;
}

CString CFileFindEx::GetLengthString() {
    CString str;
    str.Format("%lu", GetLength());
    return str;
}
 

 

5. CListCtrlEx 클래스 멤버 정의
AddItem : 리스트 컨트롤에 데이터를 입력하는 함수
  • ListCtrlEx.h 소스 보기
더보기
#pragma once
#include <afxcmn.h>
class CListCtrlEx :
    public CListCtrl
{
    DECLARE_DYNAMIC(CListCtrlEx)

public:
    CListCtrlEx();
    int AddItem(LPCTSTR strItem, int nItem, int nSubItem = 0, UINT nState = -1, int nImageIndex = -1, long nParam = -1);
    virtual ~CListCtrlEx();

protected:
    DECLARE_MESSAGE_MAP()
};
 
  • ListCtrlEx.cpp 소스 보기
더보기
#include "pch.h"
#include "ListCtrlEx.h"
#include "SearchFile.h"

IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)

CListCtrlEx::CListCtrlEx() {
}
CListCtrlEx::~CListCtrlEx() {
}

BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
END_MESSAGE_MAP()

int CListCtrlEx::AddItem(LPCTSTR strItem, int nItem, int nSubItem, UINT nState, int nImageIndex, long nParam) {
    LVITEM lvItem;
    lvItem.mask = LVIF_TEXT;
    lvItem.iItem = nItem;
    lvItem.iSubItem = nSubItem;
    lvItem.pszText = (LPTSTR)strItem;

    if (nState != -1) {
        lvItem.mask |= LVIF_STATE;
        lvItem.state = nState;
    }
    if(nImageIndex != -1){
        lvItem.mask |= LVIF_IMAGE;
        lvItem.iImage = nImageIndex;
    }
    if (nParam != -1) {
        lvItem.mask |= LVIF_PARAM;
        lvItem.lParam = nParam;
    }
    
    if (nSubItem == 0)
        return InsertItem(&lvItem);
    else
        return SetItem(&lvItem);
    
}
 

 

6. SearchFileDlg.h 작업 ①
ListCtrlEx.h, FileFindEx.h 헤더 파일 include
m_lstResult 멤버 변수의 변수 형식 변경

그림6. 헤더파일 include
그림7. m_lstResult 변수형식 변경

 

7. 리스트 컨트롤에서 사용할 아이콘 추가 작업
  • 비트맵 파일
리소스 뷰에서 추가리소스 클릭
리소스 형식에서 BitMmap 선택가져오기 클릭 후 파일 불러오기
리소스 IDIDB_LIST로 변경

그림8. 리소스 추가
그림9. 리소스 추가 화면
그림10. 비트맵 ID 변경

SMALL
8. SearchFileDlg.cpp 작업 ①
OnInitDialog 코드 추가
① 리스트 컨트롤에 이미지 연결
② 리스트 컨트롤 컬럼 추가
③ "위치" 입력창에 프로그램이 실행된 폴더 위치 보여주기

그림11. OnInitDialog 코드 추가

  • 소스 보기
더보기
    // 리스트 컨트롤에 이미지 연결
    m_img.Create(IDB_LIST, 16, 2, RGB(255, 255, 255));
    m_lstResult.SetImageList(&m_img, LVSIL_SMALL);

    // InsertColumn() : 리스트 컨트롤의 필드에 입력하는 함수
    m_lstResult.InsertColumn(0, "이름", LVCFMT_LEFT, 150);
    m_lstResult.InsertColumn(1, "위치", LVCFMT_LEFT, 150);
    m_lstResult.InsertColumn(2, "크기(byte)", LVCFMT_RIGHT, 80);
    m_lstResult.InsertColumn(3, "생성날짜", LVCFMT_CENTER, 80);
    
    // GetCurrentDirectory() : 프로그램이 실행되는 위치(폴더)를 얻어옴. 얻어진 결과는 m_strFileLocation에 입력
    char pBuf[256];
    GetCurrentDirectory(256, pBuf);
    m_strFileLocation.Format("%s", pBuf);
    UpdateData(FALSE);
 

 

9. SearchFileDlg.h 작업 ②
함수 구현
SearFileNotSub : 하위 폴더를 제외한 검색
SearFile : 하위 폴더를 포함한 검색

그림12. SearchFileDlg.h 함수 추가

 

10. SearchFileDlg.cpp 작업 ②
함수 구현
SearFileNotSub : 하위 폴더를 제외한 검색
SearFile : 하위 폴더를 포함한 검색
  • SearFileNotSub 소스 보기
더보기
// 하위 폴더를 제외한 검색 구현
void CSearchFileDlg::SearFileNotSub() {
    
    UpdateData(TRUE);

    CString strTmp, strFolder, strName;
    CFileFindEx cfile;
    int i;
    BOOL b;
    MSG msg;

    // 시작 위치를 지정. 검색 조건은 모든 파일(*.*) 이다.
    if (m_strFileLocation.Right(1) == "\\")
        strTmp = m_strFileLocation + "*.*";
    else {
        strTmp = m_strFileLocation + "\\";
        strTmp += "*.*";
    }
    
    b = cfile.FindFile(strTmp);

    while (b) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if (m_bStop)
            return;

        b = cfile.FindNextFile();

        // . ..일 경우
        if (cfile.IsDots())
            continue;

        i = m_lstResult.GetItemCount();

        // 현재 검색하는 폴더 보여주기
        m_stcStatus.SetWindowText(cfile.GetFilePath());

        // 검색 결과가 위치하는 폴더 열기
        strFolder = cfile.GetFilePath().Left(cfile.GetFilePath().ReverseFind('\\') + 1);

        // 파일(폴더)이름 얻기
        strName = cfile.GetFileName();
        
        //얻어진 결과를 대문자로 변경
        strName.MakeUpper();

        if (strName.Find(m_strToken) != -1) {    // 조건에 맞는 경우
            if (cfile.IsDirectory()) {            // 폴더이면
                // 리스트 컨트롤에 데이터 입력
                // 0번 그림과 함께 출력
                m_lstResult.AddItem(cfile.GetFileName(), i, 0, -1, 0);
                m_lstResult.AddItem(strFolder, i, 1);
                m_lstResult.AddItem("파일폴더", i, 2);
                m_lstResult.AddItem(cfile.GetCreationTimeString(), i, 3);
            }
            else {
                m_lstResult.AddItem(cfile.GetFileName(), i, 0, -1, 1);
                m_lstResult.AddItem(strFolder, i, 1);
                m_lstResult.AddItem(cfile.GetLengthString(), i, 2);
                m_lstResult.AddItem(cfile.GetCreationTimeString(), i, 3);
            }
        }
    }
}
 
  • SearFile 소스 보기
더보기
void CSearchFileDlg::SearFile(CString strStartFolder)
{
    UpdateData(TRUE);

    CString strTmp, strFolder, strName;
    CFileFindEx cfile;
    int i;
    BOOL b;
    MSG msg;

    // 시작 위치를 지정. 검색 조건은 모든 파일(*.*) 이다.
    if (strStartFolder.Right(1) == "\\")
        strTmp = strStartFolder + "*.*";
    else {
        strTmp = strStartFolder + "\\";
        strTmp += "*.*";
    }

    b = cfile.FindFile(strTmp);

    while (b) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if (m_bStop)
            return;

        b = cfile.FindNextFile();

        // . ..일 경우
        if (cfile.IsDots())
            continue;

        i = m_lstResult.GetItemCount();

        // 현재 검색하는 폴더 보여주기
        m_stcStatus.SetWindowText(cfile.GetFilePath());

        // 검색 결과가 위치하는 폴더 열기
        strFolder = cfile.GetFilePath().Left(cfile.GetFilePath().ReverseFind('\\') + 1);

        // 파일(폴더)이름 얻기
        strName = cfile.GetFileName();

        //얻어진 결과를 대문자로 변경
        strName.MakeUpper();

        if (cfile.IsDirectory()) {            // 폴더이면
            if (strName.Find(m_strToken) != -1) {
                m_lstResult.AddItem(cfile.GetFileName(), i, 0, -1, 0);
                m_lstResult.AddItem(strFolder, i, 1);
                m_lstResult.AddItem("파일폴더", i, 2);
                m_lstResult.AddItem(cfile.GetCreationTimeString(), i, 3);
            }
            SearFile(cfile.GetFilePath());    // 재귀함수 호출
        }
        else {
            if (strName.Find(m_strToken) != -1) {
                m_lstResult.AddItem(cfile.GetFileName(), i, 0, -1, 1);
                m_lstResult.AddItem(strFolder, i, 1);
                m_lstResult.AddItem(cfile.GetLengthString(), i, 2);
                m_lstResult.AddItem(cfile.GetCreationTimeString(), i, 3);
            }
        }
    }
}
 

 

11. 버튼 클릭 이벤트 추가
찾기(IDC_BUTTON_START) 클릭 이벤트 추가
멈춤(IDC_BUTTON_STOP) 클릭 이벤트 추가

그림13. 찾기 및 멈춤 버튼 클릭 이벤트 추가

  • OnClickedButtonStart 소스 보기
더보기
void CSearchFileDlg::OnClickedButtonStart()
{
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    UpdateData(TRUE);
    m_lstResult.DeleteAllItems();
    m_bStop = FALSE;

    m_strToken = m_strFileName;
    m_strToken.MakeUpper();

    if (m_bSub == TRUE) {
        SearFile(m_strFileLocation);
    }
    else {
        SearFileNotSub();
    }
    UpdateData(FALSE);
}
 
  • OnClickedButtonStop 소스 보기
더보기
void CSearchFileDlg::OnClickedButtonStop()
{
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    m_bStop = TRUE;
}
 

 

12. 실행화면

728x90
LIST