C# 기초 정리: 파일 다루기

Table of Content

System.IO 네임스페이스

  • File, Directory 클래스: 파일(디렉토리) 처리를 위한 정적 메소드 제공
  • FileInfo, DirectoryInfo 클래스: 파일(디렉토리) 처리를 위한 인스턴스 메소드 제공
  • File과 FileInfo, Directory와 DirectoryInfo 클래스는 서로 거의 같은 기능을 제공
    • 하나의 파일(디렉토리)에 한두가지 작업을 할 땐 정적 메소드를, 여러가지 작업을 할 땐 인스턴스 메소드를 주로 사용
  • File, Directory 예제는 다음 소스코드 참고
class Program
{
    public static void Main(string[] args)
    {
        /* 파일 생성 */
        FileStream fs = File.Create("a.txt");
        fs.Close();
 
        /* 파일 복사 */
        File.Copy("a.txt", "b.txt");
 
        /* 파일 삭제 */
        File.Delete("b.txt");
 
        /* 파일 이동 */
        File.Move("a.txt", "b.txt");
 
        /* 파일 속성 조회 */
        Console.WriteLine(File.GetAttributes("b.txt"));
 
        /* 파일 존재 여부 확인 */
        if (File.Exists("a.txt"))
            File.Delete("a.txt");
        if (File.Exists("b.txt"))
            File.Delete("b.txt");
 
        /* ##### 디렉토리 ##### */
 
        /* 디렉토리 생성 */
        Directory.CreateDirectory("A");
        Directory.CreateDirectory("B");
 
        /* 디렉토리 삭제 */
        Directory.Delete("B");
 
        /* 디렉토리 이동 */
        Directory.Move("A", "B");
 
        /* 디렉토리 존재 여부 확인 */
        if (Directory.Exists("A"))
            Directory.Delete("A");
        if (Directory.Exists("B"))
            Directory.Delete("B");
 
        /* 하위 디렉토리 조회 */
        string[] dirs = Directory.GetDirectories("C:\");
        foreach (string s in dirs)
            Console.WriteLine(s);
 
        /* 하위 파일 조회 */
        string[] files = Directory.GetFiles("c:\");
        foreach (string s in files)
            Console.WriteLine(s);
    }
}
  • FileInfo, DirectoryInfo 예제는 다음 소스드 참고
class Program
{
    public static void Main(string[] args)
    {
        /* 파일 생성 */
        FileInfo src = new FileInfo("a.txt");
        FileStream fs = src.Create();
        fs.Close();
 
        /* 파일 복사 */
        FileInfo dsc = src.CopyTo("b.txt");
 
        /* 파일 삭제 */
        dsc.Delete();
 
        /* 파일 속성 조회 */
        Console.WriteLine(src.Attributes);
 
        /* 파일 존재 여부 확인 */
        if (src.Exists)
            src.Delete();
        if (dsc.Exists)
            dsc.Delete();
 
        /* ##### 디렉토리 ##### */
 
        /* 디렉토리 생성 */
        DirectoryInfo dirA = new DirectoryInfo("A");
        dirA.Create();
        DirectoryInfo dirB = new DirectoryInfo("B");
        dirB.Create();
 
        /* 디렉토리 삭제 */
        dirB.Delete();
 
        /* 디렉토리 이동 */
        dirA.MoveTo("B");
 
        /* 디렉토리 존재 여부 확인 */
        if (dirA.Exists)
            dirA.Delete();
        if (dirB.Exists)
            dirB.Delete();
 
        /* 하위 디렉토리 조회 */
        DirectoryInfo dirC = new DirectoryInfo("C:\");
        DirectoryInfo[] dirs = dirC.GetDirectories();
        foreach (var v in dirs)
            Console.WriteLine(v.FullName);
 
        /* 하위 파일 조회 */
        FileInfo[] files = dirC.GetFiles();
        foreach (var v in files)
            Console.WriteLine(v.FullName);
    }
}

 

LINQ를 이용한 파일, 디렉토리 정보 조회

class Program
{
    public static void Main(string[] args)
    {
        /* 디렉토리 정보 조회 */
        string directory = "C:\";
        var directories = (from dir in Directory.GetDirectories(directory)
                           let info = new DirectoryInfo(dir) // let: LINQ의 var
                           select new
                           {
                               Name = info.Name,
                               Attributes = info.Attributes
                           }).ToList();
 
        foreach (var v in directories)
            Console.WriteLine("{0}: {1}", v.Name, v.Attributes);
 
        /* 파일 정보 조회 */
        var files = (from file in Directory.GetFiles(directory)
                     let info = new FileInfo(file)
                     select new
                     {
                         Name = info.Name,
                         Attributes = info.Attributes
                     }).ToList();
 
        foreach (var v in files)
            Console.WriteLine("{0}: {1}", v.Name, v.Attributes);
    }
}

 

System.IO.Stream

  • 스트림: 바이트(Byte) 단위로 데이터가 흐르는 통로
    • 순차접근 방식이 보통: n번째 바이트를 읽어야 n+1번째 바이트 읽기가 가능
  • System.IO.Stream은 입/출력 스트림과 순차/임의접근 방식 등을 지원
  • Stream은 추상 클래스이므로 이 클래스로부터 파생된 클래스를 사용
    • 다양한 장치를 스트림 모델 하나로 다루기 위함
    • 주요 파생 클래스: FileStream, NetworkStream, BufferedStream 등
  • FileStream 예제는 다음 소스코드 참고
class Program
{
    public static void Main(string[] args)
    {
        /* ##### 파일 쓰기 ##### */
        long someValue = 0x123456789ABCDEF; // 쓸 데이터
 
        /* 파일 스트림 생성(Create 모드) */
        Stream outStream = new FileStream("a.txt", FileMode.Create);
 
        /* long 형식 -> byte 배열 변환 */
        byte[] wBytes = BitConverter.GetBytes(someValue);
 
        /* 파일 스트림을 통해 파일에 기록
         * Write(byte 배열, 시작 오프셋, 기록할 데이터 길이) */
        outStream.Write(wBytes, 0, wBytes.Length);
 
        /* 파일 스트림 닫기 */
        outStream.Close();
        Console.WriteLine("쓰기 완료: {0:X16}", someValue);
 
        /* ##### 파일 읽기 ##### */
        byte[] rBytes = new byte[8];
 
        /* 파일 스트림 생성(Read 모드) */
        Stream inStream = new FileStream("a.txt", FileMode.Open);
 
        /* 데이터 읽기
         * Read(byte 배열, 시작 오프셋, 기록할 데이터 길이) */
        inStream.Read(rBytes, 0, rBytes.Length);
 
        /* byte 배열 -> long 형식 변환 */
        long readValue = BitConverter.ToInt64(rBytes, 0);
 
        /* 파일 스트림 닫기 */
        inStream.Close();
        Console.WriteLine("읽기 완료: {0:X16}", readValue);
    }
}

 

BinaryWriter/BinaryReader

  • FileStream은 데이터 저장 시 byte 형식으로 변환해야 하므로 불편
  • BinaryWriter/BinaryReader 클래스는 스트림에 이진 데이터(Binary Data)를 쓰기/읽기 위함
class Program
{
    public static void Main(string[] args)
    {
        BinaryWriter bw = new BinaryWriter(new FileStream("a.txt", FileMode.Create));
 
        /* BinaryWriter의 Write() 메소드는 C#이 제공하는 모든 기본 데이터 형식에 대해 오버로딩​ */
        bw.Write(12345);
        bw.Write(123.45);
        bw.Write("안녕요?ㅎ");
        bw.Close();
 
        BinaryReader br = new BinaryReader(new FileStream("a.txt", FileMode.Open));
        long size = br.BaseStream.Length;
        int a = br.ReadInt32();
        double b = br.ReadDouble();
        string c = br.ReadString();
        br.Close();
 
        Console.WriteLine(a);
        Console.WriteLine(b);
        Console.WriteLine(c);
    }
}

 

StreamWriter/StreamReader

  • 텍스트 파일 처리용
class Program
{
    public static void Main(string[] args)
    {
        StreamWriter sw = new StreamWriter(new FileStream("a.txt", FileMode.Create));
        sw.Write(12345);
        sw.WriteLine("안녕요?ㅎ");
        sw.Write(123.45);
        sw.Close();
 
        StreamReader sr = new StreamReader(new FileStream("a.txt", FileMode.Open));
        while (sr.EndOfStream == false)
            Console.WriteLine(sr.ReadLine());
        Console.WriteLine("파일 사이즈: {0}", sr.BaseStream.Length);
        sr.Close();
    }
}

 

직렬화(Serialization)

  • BinaryWriter/BinaryReader와 StreamWriter/StreamReader는 프로그래머가 정의한 복합 데이터 형식(클래스, 구조체 등)을 지원하지 않음​
  • 지원하게 하려면 데이터 형식의 필드 값을 일일이 저장하고 읽는 코드를 작성해야 함​
    • 이를 해결하기 위해 직렬화를 사용​
    • 클래스 선언부 앞에 [Serializable] 애트리뷰트를 붙여주면 직렬화 가능​
    • 필드 선언부 앞에 [NonSerialized] 애트리뷰트를 붙여주면 직렬화 안 함​
  • Stream 클래스와 BinaryFormatter를 사용하여 저장​
    • using System.Runtime.Serialization.Formatters.Binary;​
  • List 등의 컬렉션들도 직렬화 지원​
[Serializable]
class Student
{
    public String Name { get; set; }
    public int Age { get; set; }
}
 
class Program
{
    public static void Main(string[] args)
    {
        Student s = new Student() {
            Name = "김씨샵",
            Age = 18
        };
 
        /* 직렬화 */
        Stream ws = new FileStream("a.dat", FileMode.Create);
        BinaryFormatter serializer = new BinaryFormatter();
        serializer.Serialize(ws, s);
        ws.Close();
 
        /* 역직렬화 */
        Stream rs = new FileStream("a.dat", FileMode.Open);
        BinaryFormatter deserializer = new BinaryFormatter();
        Student s2 = deserializer.Deserialize(rs) as Student;
        rs.Close();
        
        Console.WriteLine("Name: {0}", s2.Name);
        Console.WriteLine("Age: {0}", s2.Age);
    }
}

 

댓글 남기기