3월 11 2016
엑셀(EXCEL) – 파일 열지않고 같은 화일인지 비교 후 중복 화일 삭제
질문의 요지는 간단한데 처리하기가 상당히 난해한 질문이 올라왔습니다.
http://www.clien.net/cs2/bbs/board.php?bo_table=kin&wr_id=3675491
일단 특정 폴더에 같은 화일을 몰아넣고? 처리하는 방법을 생각해 보았습니다.
댓글에 있는 내용이지만 몇 개면 일일이 처리할 수 있겠지만(차라리 열어보고
수작업으로 비교해도 되겠지만요) 화일이 수십개면 그 내용까지 확인하면서
비교하기란 사실 불가능에 가깝다고 봐야겠지요.
댓글에서 힌트를 얻어 MD5 해시태그를 이용하는 방법이 제일 효율적이겠다
싶어서 구걸신에게서 태그 얻는 코드를 얻었습니다. 모르는 것이 없는 분이라…
이제 자동화 시킬 순서입니다. 우선 특정 폴더를 선택하여 전체 화일의 해시태그를
화일의 이름과 함께 수집합니다. 그 수집된 해시태그를 중복값 제거하고 한쪽으로
모읍니다. 물론 중복이 없으면 똑같은 수가 나열되겠지만 중복이 있으면 데이터의
행의 크기가 달라집니다.
중복된 값이 제거된 해시태그와 수집된 해시태그의 비교를 위해 이중 루프를 돌리면서
중복된 값이 있으면 그 태그 옆에 중복된 숫자를 표시하고 다시 중복된 숫자가 1보다
크게 나타나면 화일이 똑같은 것이 한개 이상 있다는 것이므로 랜덤한 수를 발생시켜
중복 화일에 동일한 컬러를 같이 보여줍니다.
이제 사용자의 편의를 위해 몇 가지 추가 기능을 넣습니다. 우선 화일이 오픈될 때
자동으로 버튼을 추가하고 그 버튼에 화일 비교 서브루틴을 연결시킵니다. 그리고
서브 루틴이 실행되고 나면 그 결과를 출력하고 위 상단에 2개 이상이 중복된 화일을
직접 제거할 수 있는 버튼과 서브 루틴을 추가하여 바로 제거할 수 있도록 하였습니다.
Option Explicit
Public xDirect$
Private Type MD5_CTX
i(1 To 2) As Long
buf(1 To 4) As Long
inp(1 To 64) As Byte
digest(1 To 16) As Byte
End Type
Private Declare Sub MD5Init Lib “cryptdll” (Context As MD5_CTX)
Private Declare Sub MD5Update Lib “cryptdll” (Context As MD5_CTX, ByVal strInput As String, ByVal lLen As Long)
Private Declare Sub MD5Final Lib “cryptdll” (Context As MD5_CTX)
Private Function CalcMD5(strFilename As String) As String
Dim strBuffer As String
Dim myContext As MD5_CTX
Dim result As String
Dim lp As Long
Dim MD5 As String
Dim MyPointer As Long
Dim MyFlag As Boolean
MyPointer = 65535
MyFlag = False
MD5Init myContext
If FileLen(strFilename) <= 65535 Then
strBuffer = Space(FileLen(strFilename))
Open strFilename For Binary Access Read As #1
Get #1, , strBuffer
MD5Update myContext, strBuffer, Len(strBuffer)
Close #1
Else
strBuffer = Space(65535)
MyPointer = 65535
Open strFilename For Binary Access Read As #1
Do Until MyFlag = True
Get #1, , strBuffer
MD5Update myContext, strBuffer, Len(strBuffer)
If FileLen(strFilename) – MyPointer < 65535 Then
strBuffer = Space(FileLen(strFilename) – MyPointer)
Get #1, , strBuffer
MD5Update myContext, strBuffer, Len(strBuffer)
MyFlag = True
Else
MyPointer = MyPointer + 65535
strBuffer = Space(65535)
End If
Loop
Close #1
End If
MD5Final myContext
result = StrConv(myContext.digest, vbUnicode)
For lp = 1 To Len(result)
CalcMD5 = CalcMD5 & Right(“00” & Hex(Asc(Mid(result, lp, 1))), 2)
Next
End Function
‘ 영역에서 중복 항목 제거해서 지정 위치에 세로로 출력
Sub UniqItemRng(SelRng As Range, TgtRng As Range)
Dim AllCells As Range, Cell As Range
Dim NoDupes As New Collection
Dim i As Integer, j As Integer, k As Integer
Dim Swap1, Swap2, item
Set AllCells = SelRng
On Error Resume Next
For Each Cell In AllCells
If Len(Cell.Value) > 0 Then ‘ 빈셀을 포함시키지 않음
‘ Add method의 2번째 인자는 문자열이어야만 함
NoDupes.Add Cell.Value, CStr(Cell.Value)
End If
Next Cell
On Error GoTo 0
For i = 1 To NoDupes.Count – 1
For j = i + 1 To NoDupes.Count
If NoDupes(i) > NoDupes(j) Then
Swap1 = NoDupes(i)
Swap2 = NoDupes(j)
NoDupes.Add Swap1, before:=j
NoDupes.Add Swap2, before:=i
NoDupes.Remove i + 1
NoDupes.Remove j + 1
End If
Next j
Next i
For Each item In NoDupes
TgtRng.Offset(k, 0).Value = item
k = k + 1
Next item
Set Cell = Nothing
Set AllCells = Nothing
End Sub
Sub Check_Uinq_Hash()
Dim i As Integer, cnt As Integer, rclr As Integer
Dim rngC As Range, rngMD5 As Range
Dim rngR As Range, rngRef As Range
cnt = 0
Set rngRef = Worksheets(“FList”).Range(“B:B”).SpecialCells(xlTextValues)
Set rngMD5 = Worksheets(“FList”).Range(“C:C”).SpecialCells(xlTextValues)
For Each rngC In rngMD5
For Each rngR In rngRef
If rngC = rngR Then
rngC.Offset(0, 1).Value = cnt + rngC.Offset(0, 1).Value
cnt = cnt + 1
End If
Next rngR
cnt = 0
Next rngC
For Each rngC In rngMD5
If rngC.Offset(0, 1).Value >= 1 Then
rclr = Int(Rnd() * 54) + 2
For Each rngR In rngRef
If rngR = rngC Then
rngC.Interior.ColorIndex = rclr
rngC.Offset(0, 1).Interior.ColorIndex = rclr
rngR.Offset(0, -1).Interior.ColorIndex = rclr
rngR.Interior.ColorIndex = rclr
End If
Next rngR
End If
Next rngC
End Sub
Sub Make_Button()
Dim rngBtn As Range
Rows(“1:2”).Insert Shift:=xlDown
Set rngBtn = [A1:D1]
With rngBtn
ActiveSheet.Buttons.Add(.Left, .Top, .Width, .Height * 2).Select
End With
With Selection
.Caption = “화일지우기”
.OnAction = “Delete_Dup_File”
End With
rngBtn.Select
End Sub
Sub Make_Start_Btn()
Dim rngBtn As Range
Dim tgt As Worksheet
Application.DisplayAlerts = False
Application.ScreenUpdating = False
‘ 추출해서 붙여넣기할 데이터 시트가 기존에 있으면 삭제
For Each tgt In Worksheets
If tgt.Name = “Start” Then
tgt.Delete
End If
Next tgt
‘ 새 시트를 워크시트 제일 마지막에 FList라는 이름으로 추가
Set tgt = Worksheets.Add(after:=Worksheets(Worksheets.Count))
tgt.Name = “Start”
Sheets(“Start”).Activate
Set rngBtn = [C7:E7]
With rngBtn
ActiveSheet.Buttons.Add(.Left, .Top, .Width, .Height * 3).Select
End With
With Selection
.Caption = “화일 비교”
.OnAction = “Compare_Files”
End With
rngBtn.Select
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Sub Delete_Dup_File()
Dim FSO
Dim sFile As String
‘Set Object
Set FSO = CreateObject(“Scripting.FileSystemObject”)
sFile = ActiveCell.Value
‘Check File Exists or Not
If FSO.FileExists(sFile) Then
‘If file exists, It will delete the file from source location
FSO.DeleteFile sFile, True
MsgBox “삭제 완료”, vbInformation, “Done!”
Else
‘If file does not exists, It will display following message
MsgBox “화일이 존재하지 않습니다.”, vbInformation, “Not Found!”
End If
End Sub
Sub Compare_Files()
Dim xRow As Long
Dim xFname$, InitialFoldr$
Dim rngC As Range, rngRef As Range, rngMD5 As Range
Dim tgt As Worksheet
InitialFoldr$ = “C:\”
Application.DisplayAlerts = False
Application.ScreenUpdating = False
‘ 추출해서 붙여넣기할 데이터 시트가 기존에 있으면 삭제
For Each tgt In Worksheets
If tgt.Name = “FList” Then
tgt.Delete
End If
Next tgt
‘ 새 시트를 워크시트 제일 마지막에 FList라는 이름으로 추가
Set tgt = Worksheets.Add(after:=Worksheets(Worksheets.Count))
tgt.Name = “FList”
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & “\”
.Title = “Please select a folder to list Files from”
.InitialFileName = InitialFoldr$
.Show
If .SelectedItems.Count <> 0 Then
xDirect$ = .SelectedItems(1) & “\”
xFname$ = Dir(xDirect$, 7)
Do While xFname$ <> “”
Range(“A1”).Offset(xRow, 0) = xDirect$ & xFname$
xRow = xRow + 1
xFname$ = Dir
Loop
End If
End With
Set rngRef = tgt.Range(“A:A”).SpecialCells(xlTextValues)
For Each rngC In rngRef
rngC.Offset(0, 1).Value2 = CalcMD5(rngC.Value2)
Next rngC
Set rngMD5 = Worksheets(“FList”).Range(“B:B”).SpecialCells(xlTextValues)
Call UniqItemRng(rngMD5, Range(“C1”))
Call Check_Uinq_Hash
tgt.Columns.AutoFit
Call Make_Button
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
1 |
[paypal-donation] |
첨부 화일 : 20160311-파일 열지않고 같은 화일인지 비교, 삭제
3월 18 2016
엑셀(EXCEL) – 동적이름정의, VLOOKUP을 이용한 그림 참조 및 공과잡비 자동계산 견적서
질문이 간단하면 해결이 어려운 것 같습니다. 장문의 질문을 보면 어느 정도 해결의
실마리를 질문자가 알고 계셔서 아이디어만 추가하면 되는데 간결한 질문의 경우는
처음부터 시작해야해서 시간이 많이 걸리고 변수들이 많습니다.
http://www.clien.net/cs2/bbs/board.php?bo_table=kin&wr_id=3679593
자동으로 단가란에 바로 전 셀까지의 합계 * 0.1의 값이 표시되게 하고 싶습니다.
처음에는 간단하게 접근하고 그냥 기본 데이터 양식처럼 처리해서 어느 정도 해결책을
찾았는데 기존 어떤 양식에도 바로 처리할 수 있게 하다보니 정말 문제점이 많더군요.
제가 기존에 올린 여기 아이디어를 이용해 견적 오류를 줄이는 것으로 시작했습니다.
(엑셀(EXCEL) – 동적이름정의-VLOOKUP(그림참조하는 법)-주문서 작성)
우선 사용자 정의 함수를 이용해서 처리하기로 합니다. 기존 리스트 형식의 데이터로
처리하면 간단한데 견적서 양식에 바로 처리하려니 군더더기가 많은 코드가 만들어
졌습니다. 리스트 양식으로 처리하고 셀 링크를 만들어 사용하는 것을 권합니다.
일단 모듈 하나 삽입하시고 사용자 정의 함수를 만듭니다. 내용은 코멘트로 처리해
두었으니 천천히 살펴 보시고 이해하시면 되겠습니다.
Option Explicit
Function EtcCost() As Double
Dim rcnt As Integer
Dim rngSum As Double
Dim sht As Worksheet
Dim cell As Range, rngcell As Range
rngSum = 0
Set sht = Sheets(“견적서”)
‘ 더해야할 위치값 찾기
rcnt = 10 + Application.CountA(sht.Range(“F11”, sht.Range(“F26”).End(xlUp))) – 1
‘ 위치값이 현재값과 같거나 적으면 처리 안 함
If rcnt < 10 Then Exit Function
‘ 더할 위치 지정
Set rngcell = sht.Range(“I11”, sht.Range(“I” & rcnt))
‘ 순환하면서 합산
For Each cell In rngcell
rngSum = rngSum + cell.Value
Next cell
‘ 결과값 리턴
EtcCost = rngSum * 0.1
Set rngcell = Nothing
End Function
그리고 견적서 시트의 처리 코드를 입력합니다. 하나는 그냥 숨어있는 그림을 숨기고,
하나는 다 보여서 그림의 이름 정의 등이 필요할 때 사용합니다. 그리고 워크시트가
변할 때마다 VLOOKUP 함수를 사용해서 특정 셀의 이름과 그림의 이름이 같으면
보여주게 하는 것입니다.
Option Explicit
Private Sub Show_Pic_All()
Me.Pictures.Visible = True
End Sub
Private Sub Hide_Pic_All()
Me.Pictures.Visible = False
End Sub
Private Sub Worksheet_Calculate()
Dim ObjPic As Picture
Me.Pictures.Visible = False
With ActiveCell.Offset(0, 17)
For Each ObjPic In Me.Pictures
If ObjPic.Name = .Text Then
ObjPic.Visible = True
ObjPic.Top = .Top
ObjPic.Left = .Left + 5
ObjPic.ShapeRange.LockAspectRatio = msoFalse
ObjPic.Placement = xlMoveAndSize
ObjPic.ShapeRange.Width = .Width – 5
ObjPic.ShapeRange.Height = .Height * 5
Exit For
End If
Next ObjPic
End With
End Sub
그리고 단가 부분에 아래의 함수를 사용합니다.
=IF(ISBLANK(F14), “”,IF(F14=”공과잡비”,EtcCost(),VLOOKUP(F14, PicTable, 3, FALSE)))
유효성 검사를 사용한 목록에서 ‘공과잡비’란 항목이 선택되면 사용자 정의 함수를 불러와서
계산하고 아니면 VLOOKUP함수를 처리하는 것입니다. 그리고 나머지 셀에도 VLOOKUP을
처리해서 자동으로 단가, 기타 내용을 추가하시면 됩니다. 첨부 화일 참조하세요.
최대한 오류를 줄일려고 했는데 오류가 있으시면 연락? 코멘트 달아 주세요!
첨부 : 20160316-그림 참조 동적 주문서(Form)
By vinipapa • 무른모 • 0 • Tags: VLOOKUP, 견적서, 그림 참조, 동적이름정의, 부과세 자동, 엑셀