티스토리 뷰



대부분의 응용 프로그램에서 파일 관리는 필수적인 요소라 해도 지나치지 않을 만큼 매우 중요한 부분입니다. 작업 내용을 저장하거나, 저장해 놓았던 정보를 읽어 들이며, 다양한 파일을 검색하며 분석 작업을 하는 등 파일을 다루는 기능은 응용 프로그램의 가치와 활용도를 높여주는 핵심 요소입니다. 비베닷넷(비주얼베이직 닷넷, Visual Basic .Net)에서는 System.IO 네임스페이스를 통해 연관 기능을 제공하고 있습니다. 많이 사용하는 주요 클래스는 다음과 같습니다.

  • FileStream : 파일 핸들의 역할을 하면서 기본적인 파일 입출력 기능 제공

  • StreamReader, StreamWriter : 파일 스트림 기반으로 텍스트 입출력 수행

  • BinaryReader,BinaryWriter : 파일 스트림 기반으로 바이너리 입출력 수행

  • File, FileInfo : 파일의 생성, 이동, 복사, 삭제, 속성 설정, 검사를 비롯하여 파일 열기등의 기능 제공

  • Directory, DirectoryInfo : 디렉토리의 생성, 이동, 삭제, 속성 설정, 검사와 디렉토리 검색등의 기능 제공


예제를 구현하는 과정을 통해서 파일 및 디렉토리 관련 클래스에 대한 상세한 정보를 살펴볼까 합니다. 예제는 [검색] 버튼을 누르면 특정 디렉토리를 검색해서 확장자를 확인하여 텍스트 파일과 이미지 파일을 찾으면 해당 파일을 리스트 박스에 추가합니다. 리스트 박스에 출력한 파일 이름을 클릭하면 텍스트 파일인 경우는 Stream... 메소드로 내용을 읽어 텍스트 박스에 내용을 출력하고 이미지 파일인 경우에는 Binary...메소드로 내용을 읽어 그림을 출력하는 간단한 예제입니다.

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ListBox1.Items.Clear()
        Dim dir As New IO.DirectoryInfo("C:\tmp")
        Dim fname As IO.FileInfo

        For Each fname In dir.GetFiles()
            If fname.Extension.Equals(".jpg") Or fname.Extension.Equals(".png") Or
                fname.Extension.Equals(".gif") Or fname.Extension.Equals(".txt") Then
                ListBox1.Items.Add(fname)
            End If
        Next
    End Sub

위의 예제는 특정 디렉토리를 지정하여 생성한 DirectoryInfo의 오브젝트를 통해서 GetFiles() 메소드로 전체 파일 목록을 배열로 받고 배열의 각 항목을 검색하면서 확장자로 텍스트 파일이나 이미지 파일을 추출하여 리스트 박스에 추가합니다. GetFiles() 메소드는 FileInfo 오브젝트의 배열을 리턴합니다. Directory/File 클래스와 DirectoryInfo/FileInfo 클래스와의 가장 큰 차이점은 Directory/File 클래스는 다양한 기능을 수행하는 메소드가 모두 클래스 메소드, 정적(Static) 메소드이기 때문에 오브젝트를 생성하지 않아도 사용할 수 있는 반면 DirectoryInfo/FileInfo 클래스는 특정 디렉토리나 파일과 연관되어 해당 오브젝트를 통해서만 각종 메소드를 사용할 수 있는 차이가 있습니다. 위의 코드에서는 특정 디렉토리를 지정하고 있고 디렉토리 검색 과정의 파일 정보도 특정 파일과 연관한 FileInfo 오브젝트입니다. 아래는 위의 코드를 Directory/File 클래스로 구현한 예제입니다.

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ListBox1.Items.Clear()
        Dim dir As String = "C:\tmp"
        For Each fpath As String In Directory.EnumerateFiles(dir)
            If fpath.EndsWith(".jpg") Or fpath.EndsWith(".png") Or
                fpath.EndsWith(".gif") Or fpath.EndsWith(".txt") Then
                ListBox1.Items.Add(fpath.Substring(dir.Length + 1))
            End If
        Next
    End Sub

Directory/File 클래스의 경우에는 클래스 메소드를 사용하기 때문에 클래스의 오브젝트를 선언하는 과정은 찾아 볼수 없습니다. 마치 C언어에서 사용하는 파일/디렉토리 컨트롤 방식처럼 사용할 수 있습니다. 물론 편의성에 있어서는 닷넷에서 제공하는 다양한 편의 기능을 활용할 수 있으므로 비교할 수 없을 정도이기는 합니다. 


위의 그림은 특정 디렉토리를 검색해서 이미지 파일과 텍스트 파일을 추출해서 리스트 박스에 삽입한 결과 화면입니다. 어찌 되었든 파일에 대한 읽기/쓰기를 위해서는 파일을 열고(Open), 때에 따라 읽기/쓰기 위치를 이동시키며(Seek), 작업이 끝나면 닫는(Close) 과정을 거쳐야 안전하게 작업을 완료할 수 있습니다. 이 과정의 중심에 FileStream 클래스가 있습니다. FileStream 클래스의 주요 속성 및 메소드는 아래와 같습니다.

  • CanRead, CanSeek, CanWrite : 읽기/위치이동/쓰기 가능 여부 확인
  • Length, Name : 현재 파일의 크기, 이름
  • Position : 파일의 현재 위치
  • FileStream(파일경로, 파일모드, 접근모드) : 파일 스트림 오브젝트를 생성하는 다양한 오버로드 생성자가 존재하며 파일모드는 System.IO.FileMode를 사용하며 Open, Append, Create, OpenOrCreate, CreateNew, Truncate를 지정할 수 있고 접근 모드는 System.IO.FileAccess를 사용하며 Read, ReadWrite, Write를 지정할 수 있습니다. 이외에도 공유모드, 옵션, 보안 옵션등을 추가로 지정할 수 있습니다.
    FileStream() 생성자로 파일을 열 수도 있지만 FileInfo 및 File 클래스의 메소드를 통해서 
    FileStream 오브젝트를 받을 수도 있습니다.
  • Close() : 닫기
  • CopyTo(대상 스트림) : 현재 스트림을 읽어 지정한 대상 스트림에 쓰기 수행
  • Flush() : 버퍼에 있는 내용을 파일로 내보내기
  • Lock(위치, 길이), Unlock(위치, 길이) : 쓰기 방지, 해제
  • Read(버퍼, 버퍼내 위치, 길이), ReadByte() : 스트림을 읽어(길이는 최대치) 버퍼내 지정 위치에 저장
  • Seek(위치, 기준점) : 현재 파일 위치를 지정 위치로 이동시키며 기준점은 System.IO.SeekOrigin을 사용합니다. Begin, Current, End를 지정할 수 있습니다.
  • SetLength(길이) : 파일 크기 재지정
  • Write(버퍼, 버퍼내 위치, 길이), WriteByte() : 스트림 쓰기


파일에 저장하는 정보를 어떻게 인식하고 다루는가에 따라 사람이 인식할 수 있는 문자와 개행등의 일부 컨트롤 문자로 구성되는 텍스트 파일과 그 이외의 바이너리 파일로 나눌 수 있고 이러한 파일 특성에 맞추어 닷넷에서는 텍스트 파일 처리에 특성화되어 있는 StreamReader, StreamWriter 클래스를 제공하고 있습니다. 대표적인 메소드로 Peek(), Read(), ReadLine(), ReadToEnd(), Write(), WriteLine(), Flush()등을 들 수 있습니다. 닷넷에서 바이너리 파일 처리에 맞추어 제공하는 BinaryReader,BinaryWriter 클래스를 살펴보면 ReadByte, ReadBytes, ReadChar, ReadChars, ReadDecimal, ReadDouble, Readlnti6, Readlnt32, Readlnt64, ReadSByte, ReadSingle, ReadString, ReadUIntl6, ReadUInt32, ReadUlnt64 등의 메소드 처럼 파일의 내용을 정수, 실수 값등 사람이 직접 인식 하기 어려운 바이너리 값을 간편하게 처리할 수 있도록 지원하고 있습니다.


위의 그림은 이미지 파일을 클릭하면 BinaryReader 클래스를 활용하여 이미지 파일을 열고 파일 내용 전체를 버퍼에 읽은 다음 이미지 출력에 활용한 결과와 텍스트 파일을 클릭하면 StreamReader 클래스를 통해서 파일을 읽어 텍스트박스에 출력한 결과입니다. 아래는 구현한 코드 예제입니다.

Imports System.IO

Public Class Form1
    Dim dir As String = "C:\tmp"

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ListBox1.Items.Clear()
        For Each fpath As String In Directory.EnumerateFiles(dir)
            If fpath.EndsWith(".jpg") Or fpath.EndsWith(".png") Or
                fpath.EndsWith(".gif") Or fpath.EndsWith(".txt") Then
                ListBox1.Items.Add(fpath.Substring(dir.Length + 1))
            End If
        Next
    End Sub

    Private Sub ListBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) _
                     Handles ListBox1.SelectedIndexChanged
        Dim fname = dir + "\" + ListBox1.SelectedItem.ToString()
        If Not File.Exists(fname) Then
            MsgBox("파일이 존재하지 않습니다!", fname)
            Return
        End If

        TextBox1.Text = "=== " & fname & " ===" & ControlChars.CrLf
        If fname.EndsWith(".txt") Then
            Dim fs As New FileStream(fname, FileMode.Open, FileAccess.Read)
            Dim fsreader As New StreamReader(fs)
            Try
                While fsreader.Peek() > -1
                    TextBox1.Text &= fsreader.ReadLine() & ControlChars.CrLf
                End While
                fsreader.Close()
            Catch ex As IOException
                MsgBox(ex.Message)
            End Try
        Else
            Try
                Dim fs As New FileStream(fname, FileMode.Open, FileAccess.Read)
                Dim fsreader As New BinaryReader(fs)
                Dim imgbuf As Byte() = fsreader.ReadBytes(fs.Length)
                fsreader.Close()
                Dim ImageStream As MemoryStream = New MemoryStream(imgbuf)
                PictureBox1.Image = Image.FromStream(ImageStream)
            Catch ex As IOException
                MsgBox(ex.Message)
            End Try
        End If
    End Sub
End Class

이미지 파일을 픽처박스에 설정하는 방법은 다양하지만 예제를 위해서 파일 스트림을 거치도록 했습니다. 주의할 점은 코드 중간에 있는 Try... Catch...문장입니다. 네트워크와 파일등 CPU 입장에서 보면 완전 외부 세계를 다루는 부분에 대해서는 예상치 못한 다양한 예외 상황이 발생할 수 있으므로 이런 예외 상황을 감안하여 코딩하는 것이 보다 안정성 있는 코드를 만들 수 있는 방법입니다.


댓글
댓글쓰기 폼