Option Explicit
'어제 올린걸 약간 보완하는 부분이 대부분이어서 오늘은 설명이 없습니다
'삭제 부분에 대해서만 설명할것이니 이해가 잘 않되시는분 바로 아래 팁을 봐주세요
Private Type 사원
사번 As Integer
이름 As String * 10 '(영문 10문자, 한글 5문자)
입사 As Date
급여 As Long
End Type
Dim emp As 사원
Dim iFree1 As Integer
Dim iFree2 As Integer
Dim iSize As Integer
Dim iCurNum As Integer
Dim iMaxNum As Integer
Private Sub cmdAdd_Click()
If txt사번.Text <> "" And txt이름.Text <> "" And txt입사.Text <> "" And txt급여.Text <> "" Then
iMaxNum = iMaxNum + 1
With emp
.사번 = CInt(txt사번.Text)
.이름 = txt이름.Text
.입사 = CDate(txt입사.Text)
.급여 = CLng(txt급여.Text)
End With
Put #iFree1, iMaxNum, emp
Else
MsgBox "필수 항목이 누락되었습니다", vbCritical, "항목 기재"
End If
iCurNum = iMaxNum
Call Data_View
Call Active_Button
End Sub
Private Sub cmdDel_Click()
Dim i As Integer, j As Integer
'삭제 기능을 구현하는 방법입니다
'좀 까다롭게 여겨질수 있겠지만 vb 자체에서 지원해주는 개체들인 경우
'삭제나 생성시 데이터의 관리를 해당 개체에서 알아서 처리를 해주게 되지만
'파일처리시 이런 부분은 자동지원 되지 않으므로 사용자가 개별 처리를 해주어야만 합니다
'먼저 왜 이런 방법을 써야 하는지부터 생각을 좀 해보도록 하죠
'삭제란 의미는 무언가를 지운다는 뜻이 되는데
'db 의 관리나 배열의 관리 리스트박스,콤보박스의 항목등은 해당 값을 지우면
'vb 가 알아서 해당 공간또한 처리를 해주죠(깊이 생각하지 않아서 모를 뿐)
'그러나 우리가 지금 구현하고자 하는 파일처리에서는 해당 부분을 삭제시키면
'삭제된 공간에 대한 처리를 어떻게 해라~ 라는 미리 정의된 약속이 없습니다
'결국, 값은 지워버릴수 있겠지만 해당 공간이 차지하던 디스크의 공간은 계속 남게되고
'데이터의 양이 적으면 흔히 말하는 귀차니즘을 핑계삼아 그냥 두어도 무방은 합니다만
'혼자 쓰고자 프로그램 제작하는게 아니면 이런 문제 그냥 두면 큰 문제가 되겠죠
'다음 데이터로의 이동시에도 삭제된 부분은 빈 문자들 또는 써넣지도 않은 이상한 값들로
'가득 채워져서 보여지기 때문에 눈에도 거슬립니다
'** 삭제 구현 원리 **
'먼저 기존의 데이터와 같은 크기의 새로운 파일을 하나 생성합니다
'불필요한 데이터는 제외하고 꼭 있어야 하는 데이터들만 새로 생성한 파일로 옮깁니다
'작업이 다 완료되면 기존의 파일을 삭제하고 새로 생성한 파일을 기존 파일 이름으로 바꾸어줍니다
'삭제가 이루어질때마다 이런 절차를 거치게 합니다 또는 사용자가 프로그램을 종료하는 시점에서
'한번에 이루어지도록 해줍니다(가령 삭제된 데이터에는 특별한 값을 넣어서 이 값이 들어간 데이터는 삭제토록 한다던지)
'후자의 경우에는 사용자에 대한 배려이겠죠 시스템이 너무 좋아 큰 차이를 느끼지는 못하겠지만
'종료되는 시점에서 폼을 숨기도록 한다던지해서 사용자는 종료된걸로 인식하게 만들고 호박씨(?) 까는
'것처럼... 그리고 종료되었다고 느낀후에 버벅이는건 우리 프로그램 탓이 아닐거라고 생각하겠죠^^;
'이해를 돕기 위해 열려있던 버퍼1을 닫고 새로 열면서 같이 해봅니다
If iMaxNum < 2 Then Exit Sub
Close #iFree1
iFree1 = FreeFile
Open "f:\ziptmp\Employee.mdb" For Random As #iFree1 Len = iSize '삭제할 데이터가 있는 파일
iFree2 = FreeFile
Open "f:\ziptmp\New.mdb" For Random As #iFree2 Len = iSize '새로 생성된 파일
'삭제 버튼을 누를때 우리가 보고 있는 데이터가 바로 삭제될 데이터가 되겠죠
'그럼 그 데이터의 위치를 가지고 있는 변수는? iCurNum 이 되겠구요
'이 iCurNum 은 현재 지워야할 데이터가 있는 공간이고 이 공간의 값들은 새로 생성된
'파일에 복사할 필요가 없으니 루핑을 돌리되 iCurNum 공간을 제하고 돌려주면서 그 외의
'데이터들을 새로운 파일에 복사해주면 되겠습니다
For i = 1 To iCurNum - 1 '루핑의 최대값이 현재 지워질 공간보다 하나 작습니다
Get #iFree1, i, emp '해당 데이터의 값을 사용자타입에 일단 넣고
Put #iFree2, i, emp '값이 채워진 사용자타입의 데이터들을 새로 생성한 파일에 써줍니다
Next i '이해 되시나요? 중요포인트는 열린 버퍼입니다(iFree1,iFree2)
For i = iCurNum + 1 To iMaxNum '지워질 공간보다 하나 뒤의 공간부터 데이터의 최대값까지 루핑
Get #iFree1, i, emp '원본 파일에서 읽어서
Put #iFree2, i - 1, emp '생성된 파일에 써 넣는다(데이터 위치 잘 보세요 -1 입니다)
Next i
'위 데이터위치 보충설명
'가령 지워질 공간이 5라고 가정하고 지울파일이나 열린파일 모두 같은 루핑을 돌게 되니
'i 의 값은 두 파일에 모두 같은 값을 가지고 있죠
'지울 파일에서는 지워질 데이터는 취급하지 않으니 건너뛰지만
'생성될 파일또한 데이터의 위치를 지울 파일과 같이하면 중간이 공백으로 되어버립니다
'분명 하나의 데이터가 지워져야 하므로 생성된 파일에는 한칸 당겨서 저장을 해줘야죠
'이제 복사의 과정이 끝이났고 필요없는 부분은 데이터의 복사가 되지 않았으니
'새로 생성된 파일은 순수하게 필요한 데이터만 모여있겠죠
'이제 원래 있던 파일을 지우고 새로 생성한 파일 이름을 예전 파일 이름으로 바꾸어주면 됩니다
'이 작업들을 하기전에 먼저 버퍼가 열린채로 해당 파일들을 참고하고 있으니
'버퍼를 먼저 닫아야겠죠
Close #iFree1, #iFree2
Kill "f:\ziptmp\Employee.mdb" 'Kill 삭제파일 경로명
Name "f:\ziptmp\New.mdb" As "f:\ziptmp\Employee.mdb" 'Name "원본파일경로" As "바꿀 경로와 이름"
'작업이 완료되었으니 데이터의 열람을 계속 할수 있도록 버퍼를 활성시켜서 파일을 열어줍니다
'물론 지금 열리게 되는 파일은 순수한 데이터만 있는 새로 생성된 데이터가 되는것이죠
iMaxNum = iMaxNum - 1 '하나의 데이터가 삭제되었으니 데이터 최대값을 하나 줄인다
iFree1 = FreeFile
Open "f:\ziptmp\Employee.mdb" For Random As #iFree1 Len = iSize
' If LOF(iFree1) / iSize = 0 Then
' iMaxNum = 1
' iCurNum = 1
' End If
Call Data_View
End Sub
Private Sub cmdFirst_Click()
If iCurNum < 2 Then
MsgBox "데이터가 존재하지 않습니다", vbInformation, "이동 불가"
Else
iCurNum = 1
Call Data_View
End If
End Sub
Private Sub cmdLast_Click()
If iCurNum = iMaxNum Then
MsgBox "데이터가 존재하지 않습니다", vbInformation, "이동 불가"
Else
iCurNum = iMaxNum
Call Data_View
End If
End Sub
Private Sub cmdNext_Click()
If iCurNum = iMaxNum Then
MsgBox "데이터가 존재하지 않습니다", vbInformation, "이동 불가"
Else
iCurNum = iCurNum + 1
Call Data_View
End If
End Sub
Private Sub cmdPrev_Click()
If iCurNum < 2 Then
MsgBox "데이터가 존재하지 않습니다", vbInformation, "이동 불가"
Else
iCurNum = iCurNum - 1
Call Data_View
End If
End Sub
Private Sub Form_Load()
iFree1 = FreeFile
iSize = LenB(emp) '이번 내용은 가변길이 문자가 없는 관계로 식별자 포함 않됩니다
Open "f:\ziptmp\Employee.mdb" For Random As #iFree1 Len = iSize
iMaxNum = LOF(iFree1) / iSize
If iMaxNum = 0 Then
iMaxNum = 1
End If
iCurNum = 1
Call Data_View
Call Active_Button
Debug.Print iMaxNum
End Sub
'어제와는 좀 다르게 중복되는 코딩은 프로시져를 만들어 호출만 해주는 방식으로 바꿨습니다
'자주 사용되는 코드인경우 이렇게 만들어두면 코드의 양도 많이 줄어들게 되고
'너저분한 코드가 줄어들어 가독성도 높아지겠죠
'다른 언어에서는 서브프로시져와 함수란 개념자체가 없다고 합니다
'내부적으로 다르지 않기 때문이라는군요 그러나,vb 에서는 두 방식을 구분해서 표현하므로
'잠깐 짚고 넘어가도록 하죠
'아래처럼 특정한 값을 참조하지 않고 그냥 맡겨진 일을 수행하는 방법이 있고
'Private Sub Data_View(ctl as Control) 와 같이 특정한 개체를 참조하게 할수도 또는 특정값을
'참조할수도 있습니다 이런 경우를 서브루틴 또는 서브 프로시져 라고 부르게 되구요
'Function Data_View(ctl as Control)As Long 와 같이 괄호 밖으로 특정 타입이 또 한번 나오게
'되는 경우 vb 에서는 함수 또는 펑션 이라고 부릅니다
'이 경우 서브 프로시져와는 달리 자체적으로 수행한 특정 결과값을 괄호 밖으로 선언한 특정 타입으로
'반환해주게 됩니다
'내부적 처리는 비슷하게 흘러가지만 반환값이 있는지 없는지에 따라 함수 또는 프로시져라고
'달리 불리어진다는 차이점만 아시면 되겠습니다
Private Sub Data_View()
If iMaxNum >= 1 Then
Get #iFree1, iCurNum, emp
With emp
txt사번.Text = .사번
txt이름.Text = .이름
txt입사.Text = .입사
txt급여.Text = .급여
End With
Else
MsgBox "표시할 데이터가 존재하지 않습니다", vbInformation, "데이터 없슴"
End If
End Sub
Private Sub Active_Button()
If iMaxNum < 2 Then
cmdFirst.Enabled = False
cmdPrev.Enabled = False
cmdNext.Enabled = False
cmdLast.Enabled = False
cmdDel.Enabled = False
ElseIf iMaxNum > 2 Then
cmdFirst.Enabled = True
cmdPrev.Enabled = True
cmdNext.Enabled = True
cmdLast.Enabled = True
cmdDel.Enabled = True
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
Close #iFree1
End Sub