[C#] 파일명이 중복일 때 자동으로 이름을 생성하는 코드

1. 개요


여러개의 폴더에서 하나의 폴더로 파일을 복사 / 이동 하는 프로그램을 작성한다고 하자.
기존에 파일 이름이 있을 때는 그 이름을 가진 파일에 덮어쓰는 형식이 아닌 새로운 이름을 붙여서 저장하고 싶을 경우가 있다.
윈도우즈의 중복파일 명명 방식과 같이
예를 들어 test.txt 파일이 기존에 존재하고 그 파일이름과 같은 파일을 추가로 저장하고 싶을 때
test (2).txt로 이름을 지어주는 방식의 코드를 소개한다.

2. 주의점


a) 파일명에 '?', '<', '>', '\', '/', '|' 와 같은 특수기호를 사용하면 파일을 저장시 Exception이 발생하기 때문에 그런 기호들은 사전에 제거한다.

b) test (2).txt과 같은 파일의 새로운 이름은 test (3).txt 와 같이 중복이름의 개수를 파악할 수 있게 생성한다.

c) test (2)(2).txt 과 같은 파일이 존재하고 이 파일에 대한 새로운 이름을 부여할 때, text (3)(2).txt 와 같이 앞의 괄호보다는 마지막 괄호 안의 숫자를 test (2)(3).txt 와 같이 증가시켜준다.

3. 코드 설명

using System.IO;
using System.Text.RegularExpressions;

string GetAvailablePathname(string folderPath, string filename)

{
    int invalidChar = 0;
    do
    {
        invalidChar = filename.IndexOfAny(Path.GetInvalidFileNameChars());

        if (invalidChar != -1)
            filename = filename.Remove(invalidChar, 1);
    }
    while (invalidChar != -1);


    string fullPath = Path.Combine(folderPath, filename);
    string filenameWithoutExtention = Path.GetFileNameWithoutExtension(filename);
    string extension = Path.GetExtension(filename);


    while (File.Exists(fullPath))
    {
        Regex rg = new Regex(@".*\((?<Num>\d*)\)");
        Match mt = rg.Match(fullPath);


        if (mt.Success)
        {
            string numberOfCopy = mt.Groups["Num"].Value;
            int nextNumberOfCopy = int.Parse(numberOfCopy) + 1;
            int posStart = fullPath.LastIndexOf("(" + numberOfCopy + ")");

            fullPath = string.Format("{0}({1}){2}", fullPath.Substring(0, posStart), nextNumberOfCopy, extension);
        }
        else
        {
            fullPath = folderPath + filenameWithoutExtention + " (2)" + extension;
        }
    }
    return fullPath;
}


a) Path.GetInvalidFileNameChars()를 호출하면 파일명에 들어갈 수 없는 문자들을 배열로 던져준다.
(Path.InvalidPathChars 라는 Property가 있었으나 현재는 deprecated 되었다.)

b) Path class에는 유용한 함수들이 미리 구현되어 있다.
 Combine() : 두개의 Path 혹은 Path + 파일명을 붙여주는 함수이다. 이 함수가 필요한 이유는 Path와 파일명을 더할 때 흔히 string1 + "\\" + string2 과 같은 형식으로 사용하게 되는데  string1에서 마지막 문자열이 '\'로 끝나는 경우 원치않는 결과를 가져올 수 있기 때문이다
GetFileNameWithoutExtension() : 파일의 확장자를 제외한 파일의 이름만 던져준다.
GetExtension() : 파일 확장자만 던져준다.

c) 파일이 이미 존재하는 지 판단할 때는 File.Exists() 함수를 이용하면 간단하게 알 수 있다.

d) 파일명에 괄호가 존재할 경우 그 괄호안의 숫자를 판단하는 방법으로 Regular Expression(정규식)을 사용하였다.
Regex class는 System.Text.RegularExpressions namespace 안에 정의되어 있다.
여기에서 사용한 ".*\((?<Num>\d*)\)" 은 input string 중에서 마지막의 괄호의 묶음을 찾고 괄호안의 숫자를 Num라는 그룹이름으로 Capture 하는 pattern이다. 이러한 패턴을 사용하여 입력문자열을 Match() 함수를 통해 넣었을 경우 Match class 형태로  리턴하게 되는데 Match.Groups[]로 ('[ ]' 사이에는  Group Index가 들어갈 수 있고, 단순히 Group 이름의 문자열도 들어갈 수 있다) Capture한 Group에 접근한다.
C# 에서 사용하는 정규식을 쉽게 만드려면 http://www.ultrapico.com/Expresso.htm 와 같은 툴을 참고하기 바란다.

e) int.Parse() 함수를 통하여 string을 int 타입으로 변환할 수 있다.

f) 마지막으로 위의 주의점 c)에 보면 마지막 괄호를 변경하고 싶기 때문에 마지막 괄호가 나타나기 전까지의 문자열을 자르고 위의 기존의 숫자에 증가된 숫자와 파일 확장자를 재구성 하여 full path를 만든다.


4. 샘플 프로그램

Visual Studio 2008을 이용하여 샘플 프로그램을 만들어 보았다.
C:\ 폴더 밑에 test.txt를 생성하는 프로그램인데, 실행 시마다 새로운 파일이름으로 생기는 것을 확인 할 수 있을 것이다.

chaoskcuf
tags : , , ,
프로그래밍/TIP& Study 2008/01/16 11:16

트랙백 주소 : http://chaoskcuf.com/trackback/127

댓글을 달아 주세요

  1. 김시억 2009/03/13 21:48  수정/삭제  댓글쓰기

    중복제거에관한건데요 텍스트화일을 불러들여 중복제거를 하려고합니다
    처음인데 막상시작하려하니 희안하게 로직이 잘 안떠오르는군요///
    제가 1년좀 안되는데요 c#만 ....한번도 안해봐서 텍스트중복은;;;

    aa
    aa
    bb
    bb

    이렇게 있다고 할경우 저 텍스트화일을 중복제거해서
    aa
    bb
    이렇게만 결과물이 나오게하려면 어떻게 해야하나요?
    쉬운거 같으면서도 막상코딩하려니 로직이 감이 잘 안잡히네요 ㅠ.ㅠ
    답변부탁드립니다

    • chaoskcuf 2009/03/13 23:17  수정/삭제

      http://chaoskcuf.com/entry/C-파일에서-중복을-제거하는-방법

      위의 URL에 포스팅했습니다.

  2. 2012/02/06 15:04  수정/삭제  댓글쓰기

    고맙습니다.

Powerd by Textcube, designed by criuce
rss