[.NET] 파일 이름 변경, 복사할 때 동일한 파일이 있으면 자동으로 넘버링 해 주기.

 

 

윈도우 탐색기에서 파일 복사하기. 많이 쓰이는 기능입니다.

윈도우 탐색기 파일 복사의 특징 중 하나는 동일한 파일을 동일한 위치에 복사&붙여넣기를 계속 시도하면

 

"파일명 - 복사본"

"파일명 - 복사본 - 복사본"

"파일명 - 복사본 - 복사본 - 복사본"

 

이와 같이 자동으로 " - 복사본" 이라는 명칭을 덧붙여 새로운 사본을 생성시킨다는 것을 알고 계시죠.

 

폴더의 경우, '새 폴더' - '새 폴더(1)' - '새 폴더(2)' - '새 폴더(3)'  과 같이 순차적으로 번호매김을 해 줍니다.

 

이것과 유사한 기능을 하는 함수입니다.

닷넷에서 임의로 디스크의 파일을 복사하거나 이동하거나 이름바꾸기를 할 때 해당 파일의 존재 여부를 확인하고 자동으로 적절한 넘버링을 붙여주는 함수입니다.

 

 

VB.NET 코드 :

 

    Public Shared Sub RenameFileExt(srcFileNM As String, ByRef tgtFileNM As String)
        Dim count As Integer = 1
        Dim FileNameOnly As String = System.IO.Path.GetFileNameWithoutExtension(tgtFileNM)
        Dim Extension As String = System.IO.Path.GetExtension(tgtFileNM)
        Dim path As String = System.IO.Path.GetDirectoryName(tgtFileNM)
        Dim newFullPath As String = tgtFileNM

        While File.Exists(newFullPath)
            count += 1
            Dim tmpFileNM As String = String.Format("{0} ({1})", FileNameOnly, count)
            newFullPath = System.IO.Path.Combine(path, tmpFileNM + Extension)
        End While

        Try
            File.Move(srcFileNM, newFullPath)
            tgtFileNM = newFullPath
        Catch ex As Exception
        End Try

    End Sub

 

 

C#.NET 코드 :

 

public static void RenameFileExt(string srcFileNM, ref string tgtFileNM)
{
	int count = 1;
	string FileNameOnly = System.IO.Path.GetFileNameWithoutExtension(tgtFileNM);
	string Extension = System.IO.Path.GetExtension(tgtFileNM);
	string path = System.IO.Path.GetDirectoryName(tgtFileNM);
	string newFullPath = tgtFileNM;

	while (File.Exists(newFullPath)) {
		string tmpFileNM = string.Format("{0} ({1})", FileNameOnly, count++);
		newFullPath = System.IO.Path.Combine(path, tmpFileNM + Extension);
	}

	try {
		File.Move(srcFileNM, newFullPath);
		tgtFileNM = newFullPath;
	} catch (Exception ex) {
	}

}

 

 

인수로 주어지는 타겟파일명을 ByRef로 한 이유는, 함수 내부에서 타겟파일명이 변경될 수 있기 때문입니다.

RenameFileExt("C:\111.txt", "C:\111.txt") 라고 넣는다면, 소스와 타겟이 동일하므로

C:\111 (1).txt 라는 파일로 타겟파일명을 바꿔주게 되겠죠. 이 최종 파일명 정보를 리턴하는 것입니다.

 

File.Copy 메서드로 바꿔서 사용하면  윈도우 탐색기의 복사 기능과 비슷한 로직으로 사본을 생성하게 됩니다.

저는 Rename을 위해 File.Move메서드를 사용했습니다.

 

많이 활용하시길...

 

[.net] ADO (6.0) + ODBC드라이버를 이용한 DB Connection (MS-SQL, Excel, Access)

 

 

Microsoft ActiveX Data Objects 6.0 Library (adodb)와 ODBC 를 이용해서 각 DB에 Connection하는 클래스

 

 

Public Class DBConn
    Public myDB As New ADODB.Connection
    Public myRS As New ADODB.Recordset
    Public qq As StringBuilder

    Public Function DBOpen() As Boolean
        Dim Opened As Boolean
        Try
            myDB.Open("Provider=SQLOLEDB.1;Persist Security Info=False;Data Source=111.111.111.111,1111;Initial Catalog=DBNAME;User ID=DBNAME;Password=DBPASS;")

            If myDB.State Then
                Opened = True
            Else
                Opened = False
            End If
        Catch ex As Exception
            Opened = False
        End Try
        myRS.CursorType = ADODB.CursorTypeEnum.adOpenStatic
        myRS.CursorLocation = ADODB.CursorLocationEnum.adUseClient
        myRS.LockType = ADODB.LockTypeEnum.adLockOptimistic

        DBOpen = Opened
    End Function


    Public Sub DBClose()
        Try
            myDB.Close()
            loFunctions.releaseObject(myDB)
        Catch ex As Exception
        End Try
    End Sub

End Class




Public Class xlDBConn
    Public xlDB As New ADODB.Connection
    Public xlRS As New ADODB.Recordset
    Public qq As StringBuilder

    Public Function xlDBOpen(xlFileNM As String) As Boolean
        Dim Opened As Boolean

        Try
            With xlDB
                .ConnectionString = "Dsn=Excel Files;dbq=" + xlFileNM + ";driverid=1046;fil=excel 12.0;maxbuffersize=2048;pagetimeout=5"
                .Open()
            End With

            If xlDB.State Then
                Opened = True
            Else
                Opened = False
            End If
        Catch ex As Exception
            Opened = False
        End Try

        xlDBOpen = Opened
    End Function


    Public Sub xlDBClose()
        Try
            xlDB.Close()
            loFunctions.releaseObject(xlDB)
        Catch ex As Exception
        End Try
    End Sub

End Class



Public Class aceDBConn
    Public aceDB As New ADODB.Connection
    Public aceRS As New ADODB.Recordset
    Public qq As StringBuilder

    Public Function aceDBOpen(aceFileNM As String) As Boolean
        Dim Opened As Boolean

        Try
            With aceDB
                .ConnectionString = "Dsn=MS Access Database;dbq=" + aceFileNM.Replace("\\", "\") + ";driverid=25;fil=MS Access;maxbuffersize=2048;pagetimeout=5;uid=admin"
                .Open()
            End With

            If aceDB.State Then
                Opened = True
            Else
                Opened = False
            End If
        Catch ex As Exception
            Opened = False
        End Try

        aceDBOpen = Opened
    End Function


    Public Sub aceDBClose()
        Try
            aceDB.Close()
            loFunctions.releaseObject(aceDB)
        Catch ex As Exception
        End Try
    End Sub


End Class

 

[.NET] 디렉토리의 파일 목록 조사 + 필터링. Linq와 람다식을 이용한 Directory.GetFiles 확장자 지정하기.

 

 

사용자에게 폴더를 선택하게끔 하고, 해당 폴더 안에 들어있는 파일을 리스트업 해줘야 할 때가 있다.

.NET에서는  System.IO.Directory.GetFiles 를 이용해서 디렉토리 내 파일 목록을 얻어올 수 있다.

사용방법은 잘들 아시겠지만 다음과 같다.

 

Dim DataFileNM As String() = Directory.GetFiles(TargetFolderNM, "*.*", SearchOption.TopDirectoryOnly)

 

여기서 보듯이 GetFiles메서드에는 패턴검색 옵션을 지정할 수가 있게 되어있는데(searchpattern)

이 패턴 옵션이 뭔가 어정쩡하다.

 

예를들어, 폴더 내의 이미지파일을 모두 보여주고 싶을 때에는 파일확장명에 *.gif, *.tif, *.jpg, *.png, *.bmp 가 지정되어야 할 것이다.

하지만 익숙한 확장자 나열 기법을 적용해서

Directory.GetFiles(TargetFolderNM, "*.gif|*.jpg|*.png", SearchOption.TopDirectoryOnly) 처럼 사용하면 에러가 발생한다.

searchpattern에는 와일드카드를 사용할 수 있지만, 조건식을 나열할 수는 없는 반쪽짜리인 것이다..-_-

꼭 단일 확장자로만 지정을 해줘야 한단다.

 

그래서 그럼 이렇게 해보았다. Concat메서드로  리턴된 배열을 합쳐버리는 방법이다.

 

DataFileNM = Directory.GetFiles(TargetFolderNM, "*.jpg", SearchOption.TopDirectoryOnly)
DataFileNM = DataFileNM.Concat(Directory.GetFiles(TargetFolderNM, "*.tif", SearchOption.TopDirectoryOnly).ToArray)

 

하지만 이 방법 역시 경우에 따라서 오류가 발생한다.

Concat 메서드는 연결할 첫 번째 시퀀스가 nothing일 경우 ArgumentNullException 에러를 발생시킨다.

즉, 첫번째줄에서 *.jpg파일이 하나도 발견되지 않았다면  *.tif 에서 반환된 파일목록 배열은 붙을곳을 찾지 못해 오류가 나는 것이다..

모든 폴더에 jpg파일이 최소한 한개씩은 있어준다는 보장이 없으니 이 역시 사용불가이다. 물론 이것도 조건분기를 처리해서 DataFileNM이 Nothing일 경우엔 그냥 할당하고  아닐경우에만 Concat을 하는 식으로 코딩할 수는 있겠으나 바람직한 코딩이 아니다.

 

 

사설이 길었는데, 이러한 연유로 아래의 방식을 찾았다.  별도의 함수를 만들지 않아도 되고 코드 길이도 짧다.

실로 베스트한 방식이 아닐수 없다. 후후후 -_ㅡv

여기엔 Linq와 람다식이 사용되었다.

 

[VB.net]

'***** 지정된 폴더에서 특정 이미지 파일만 찾아온다.
Dim DataFileNM As String()
Dim exts As String() = {".tif", ".jpg", ".gif"}

 

DataFileNM = Directory.GetFiles(TargetFolderNM, "*.*", SearchOption.TopDirectoryOnly).Where(Function(s) exts.Contains(Path.GetExtension(s), StringComparer.OrdinalIgnoreCase)).ToArray 

 

[C#.net]

string[] exts = new [] {".tif", ".jpg", ".gif"};

string[] DataFileNM =  Directory.GetFiles(TargetFolderNM, "*.*", SearchOption.TopDirectoryOnly).Where(s=>exts.Contains(Path.GetExtension(s), StringComparer.OrdinalIgnoreCase)).ToArray;

 

 

일단  exts에 필터링 할 확장자를 배열로 지정해 놓고

Directory.GetFiles(TargetFolderNM, "*.*", SearchOption.TopDirectoryOnly) 로 폴더내 모든 파일을 가져온다(String배열)

여기서 .Where(Function(s) exts.Contains(Path.GetExtension(s), StringComparer.OrdinalIgnoreCase)) 으로  확장자를 필터링해서 .ToArray로 다시 변환해서 리턴하는 것이다.

 

그러면 DataFileNM 스트링배열 개체에  해당 파일명이 아름답게 담겨지게 된다!

 

 

 

[.NET] 시스템 환경변수 Path에 특정 경로 추가하기.

 

프로그램을 만들어 배포를 하게되면 경우에 따라 System 환경 변수의 Path를 건드려 주어야 할 때가 있다.

 

 

헌데 없어보이게  사용자에게 직접 환경변수를 추가하라고 할 수는 없는 노릇이고

제일 무난하고 편한 Install Factory로 해도, Install Shield 로 해도 방법이 없는것은 아니지만 해본결과 별루이다.

레지스트리를 직접 변경해주는 방식으로 하게 되는데, 이때 기존의 Path내용을 유지하면서 새로운것만 추가하기가 간단치 않다.

 

일단 '사용자 환경변수' 레지스트리의 위치는

 HKEY_CURRENT_USER\Environment\  이다.

사용자변수는 간단하다.

문제는 시스템 환경변수이다. 시스템환경변수는 최소 두군데 이상 동시에 존재한다.

일단 기본위치는

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

이곳이지만, 사용자계정에따라 ControlSet001, ControlSet002 ... 등등으로 나뉘어진다.

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment

어드메 있는것을 바꿔야 하는지까지는 잘 모르겠다. 이미 이렇게 널부러져 있는것을 확인한순간 다른방법을 고민했으니..

 

 

.NET에는 System.Environment 라는 훌륭한 클래스가 기본제공되질 않는가!

그래서 방법은 프로그램 실행시 시스템 환경변수값을 불러다가  내가 추가하고자 하는 경로가 이미 존재하면 제껴버리고,

없으면  맨앞에 경로를 하나 추가해서 다시 셋팅해주는 것이다.

그게 ControlSet001이 수정되야 하는지 002가 수정되야 하는지, 아니면 CurrentControlSet 에서 수정되야 하는지 알필요 따윈 없다.

어차피 이 프로그램이 System.Environment 가  찾아내준 위치의 시스템환경변수값만 조작해주면 DLL을 불러들이는데는 지장이 없으니까.

 

그래서 작성한 코드.

 

    Public Shared Sub SystemPathControl(AppPath As String)

        Dim _sysPath As String = System.Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine)
        Dim oldPath() As String = _sysPath.Split(";")
        Dim newPath As New StringBuilder

        If Not oldPath.Contains(AppPath) Then
            newPath.Append(AppPath + ";")
            For Each ePath As String In oldPath
                newPath.Append(ePath + ";")
            Next
            System.Environment.SetEnvironmentVariable("Path", newPath.ToString, EnvironmentVariableTarget.Machine)
        End If

    End Sub

 

 

사용된 클래스는 보시다시피..

System.Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine)

System.Environment.SetEnvironmentVariable("Path", newPath.ToString, EnvironmentVariableTarget.Machine)

이 되겠다.

Get으로 Machine(시스템) 환경변수 중 Path를 가져와서 매개변수로 들어온 AppPath값이 있는지 찾아보구

없으면 젤앞에 AppPath를 붙이고 나머지껄 줄줄이 이어붙여서 newPath를 만들어준 다음

Set으로 다시 Machine의 Path값을 바꿔주는 초간단 함수가 되겠다.

Get/Set EnvironmentVariable 메서드의 마지막 매개변수는 사용자/시스템 변수값에 대한 상수이다.

시스템변수는 EnvironmentVariableTarget.Machine

사용자변수는 EnvironmentVariableTarget.User

 

 

이제 이것을 프로그램 시작할때 도는 프로시져 한귀퉁이에서 호출해주면 되시겠다.

사실 이 행위를 플그램 실행때마다 매번 하는게 솔직히 비효율적일 수가 있다.

어디서 지나가다 주워본것 같은데, 닷넷은 배포후 최초 실행되었는지를 리턴해주는 함수가 있다고 봤다(다시 찾아보려니 찾을수가 없지만 ㅜㅜ)

이걸 조합한다면  프로그램 인스톨 후 최초 실행시에만 한번 돌려주도록 만들 수도 있을것이다.

 

최초실행여부를 확인해 주는 함수를 아시는분은 댓글로 제보좀 부탁드립니다 ㅋㅋ 

+ Recent posts