C#/C# 교과서

[C# 교과서] 58. 스트림과 파일 입출력 맛보기

서니션 2023. 2. 10. 14:54
728x90
반응형

프로그램 코드에서 작성된 데이터는 목적에 따라 영구적으로 보관해야 할 때가 있음

이 때는 파일이나 데이터베이스에 저장


System.IO 네임스페이스

C#을 사용하여 파일에 대한 입력과 출력을 담당하는 네임스페이스는 System.IO

 

<자주 사용하는 파일 처리 관련 API>

  • File.Exists() : 지정된 경로에 파일이 있으면 true를 반환, 없으면 false 반환
  • new DirectoryInfo().Parent.FullName : 지정된 경로의 부모 폴더 값 반환
  • Path.GetDirectoryName() : 지정한 경로의 디렉토리 값 반환
  • Path.Combile() : 경로 2개를 합치거나 경로와 파일 이름을 묶어서 반환
  • Directory.Exists() : 지정된 디렉터리가 있는지 확인
  • Directory.CreateDirectory() : 디렉터리 생성
  • Directory.Delete() : 디렉터리 삭제
  • Path.GetFileName() : 파일 이름 추출
  • Path.GetExtension() : 파일 확장자 추출
  • File.Copy() : 파일 복사
  • File.Move() : 파일 이동
  • Directory.GetFiles() : 지정된 경로의 파일 이름 리스트를 문자열 배열로 반환
  • File.ReadAllText() : 텍스트 파일 읽기
  • File.WriteAllText() : 텍스트 파일 쓰기
  • File.ReadAllLines() : 텍스트 파일의 모든 줄을 읽어 문자열 배열로 반환
  • File.WriteAllLines() : 문자열 배열을 줄 단위로 텍스트 파일에 저장
  • File.AppendAllText() : 텍스트 파일에 내용 추가
  • File.AppendAllLines() : 컬렉션 형태의 문자열 추가
  • File.ReadAllBytes() : 바이너리 파일 읽기
  • File.WriteAllBytes() : 바이너리 파일 쓰기

 

<파일 처리에서 많이 사용하는 File과 Stream 클래스>

  • File 클래스 : File 클래스는 사용하기 편함. 다만 모든 내용을 다 읽어 처리하기에 대용량 파일을 처리할 때는 메모리를 관리하기 어려움. File 클래스는 텍스트 파일 및 간단한 바이너리 파일을 다룰 때 권장
  • Stream 클래스 : File 클래스와 달리 Stream 클래스는 모든 데이터를 메모리에 올려 두지 않고 사용하기에 대용량 파일 처리 효과적

문자열에서 파일 이름 추출하기

using System;

class GetFileNameDemo
{
    static void Main()
    {
        // 아래 전체 경로가 입력되었을 때 파일 이름과 확장자 추출
        // 입력
        string dir = "C:\\Program Files\\Git\\git-cmd.exe";
        string fullName = String.Empty;
        string name = "";
        string ext = name;

        // 처리
        // 전체 파일 이름 : 마지막 \\ 위치 값 + 1한 위치부터 마지막까지 검색
        fullName = dir.Substring(dir.LastIndexOf('\\')+1);
        name = fullName.Substring(0, fullName.LastIndexOf('.'));
        ext = fullName.Substring(fullName.LastIndexOf('.')+1);

        // 출력
        Console.WriteLine($"전체 파일 이름 : {fullName}");
        Console.WriteLine($"순수 파일 이름 : {name}");
        Console.WriteLine($"확장자 : {ext}");
    }
}

이러한 방식말고도 Path 클래스의 주요 메서드를 사용하면 편리하게 기능 구현 가능


Path 클래스로 파일 이름 및 확장자, 폴더 정보 얻기

> var dir = "C:\\Program Files\\Git\\git-cmd.exe";
> Path.GetFileName(dir)
"git-cmd.exe"
> Path.GetFileNameWithoutExtension(dir)
"git-cmd"
> Path.GetExtension(dir)
".exe"
> Path.GetDirectoryName(dir)
"C:\\Program Files\\Git";
> Path.GetFullPath(dir)
"C:\\Program Files\\Git\\git-cmd.exe";

파일과 디렉터리 관련 클래스

파일을 생성하고 삭제하는 일반적인 절차는 다음과 같음

  1. StreamWriter 클래스를 사용하여 텍스트 파일 쓰기
  2. StreamReader 클래스를 사용하여 텍스트 파일 읽기
  3. File과 FileInfo 클래스로 파일 정보 얻기
  4. Directory와 DirectoryInfo 클래스로 폴더 정보 얻기

 

<텍스트 파일을 만들고 문자열 저장하기>

using System;
using System.IO;

class StreamWriterLineDemo
{
    static void Main()
    {
        string data =
        "안녕하세요 \r\n반갑습니다." + Environment.NewLine + "또 만나요.";

        // 1. StreamWriter 클래스를 사용하여 파일 생성
        // C드라이브에 Temp 폴더를 미리 생성해야 함
        StreamWriter sw = new StreamWriter("C:\\Temp\\Test.txt");

        // 2. Write() 메서드: 저장
        sw.WriteLine(data);

        // 3. StreamWrite 개체를 생성했으면 반드시 닫기
        sw.Close();

        // 4. 메모리 해제
        sw.Dispose();
    }
}

C 드라이브의 Temp 폴더에 Test.txt 파일이 만들어지고

data 변수에 지정된 문자열 값지 저장

 

Environment.NewLine 값은 텍스트 파일에서 줄 바꿈을 나타냄

 

1의 StreamWriter 같은 파일 처리 관련 클래스의 인스턴스를 사용했다면,

반드시 3과 4처럼 닫기와 해제 작업을 하는 것이 좋음

 

<텍스트 파일의 내용을 읽어 출력하기>

using System;
using System.IO;

class StreamReadDemo
{
    static void Main()
    {
        string data =
        "안녕하세요 \r\n반갑습니다." + Environment.NewLine + "또 만나요.";

        // 1. StreamReader 클래스로 텍스트 파일 읽기
        // C드라이브에 Temp 폴더를 미리 생성해야 함
        StreamReader sr = new StreamReader("C:\\Temp\\Test.txt");

        // 2. ReadToEnd() 메서드로 텍스트 파일의 내용을 읽어 콘솔에 출력
        Console.WriteLine("{0}", sr.ReadToEnd()); // 전체 읽어오기

        // 3. 사용 후 파일을 닫고 메모리 정리
        sr.Close();
        sr.Dispose();
    }
}

3처러 Close()와 Dispose() 메서드를 호출하여 메모리를 정리하는 작업을 하면 좋음

그렇지 않으면 파일이 사용 중이라는 에러를 만날 수 있음

 

<텍스트 파일 정보 얻기>

using System;
using System.IO;

class StreamReadDemo
{
    static void Main()
    {
        string file = "C:\\Temp\\Test.txt";

        // 1. 파일 클래스 : 정적 멤버 제공
        if (File.Exists(file)) // 파일이 있다면
        {
            Console.WriteLine("{0}", File.GetCreationTime(file));
            File.Copy(file, "C:\\Temp\\Test2.txt", true); // 파일 복사 테스트
        }

        // 2. Fileinfo 클래스 : 인스턴스 멤버 제공
        FileInfo fi = new FileInfo(file);
        if (fi.Exists) // 파일이 있다면
        {
            Console.WriteLine($"{fi.FullName}"); // 파일 이름 출력
        }
    }
}

 

파일을 다룰 때는 이 예제처럼 정적 클래스인 File 또는 인스턴스 클래스인 FileInfo를 사용해도 동일한 결과 나옴

 

<폴더 정보 얻기>

using System;
using System.IO;

class DirectoryDemo
{
    static void Main()
    {
        string dir = "C:\\";

        // 1. 디렉토리 클래스
        if (Directory.Exists(dir))
        {
            Console.WriteLine("[1] C 드라이브의 모든 폴더 목록 출력");
            foreach (string folder in Directory.GetDirectories(dir))
            {
                Console.WriteLine($"{folder}");
            }
        }

        // 2. DirectoryInfo 클래스
        DirectoryInfo di = new DirectoryInfo(dir + "Temp\\");
        if (di.Exists)
        {
            Console.WriteLine("[2] C 드라이브 Temp 폴더의 모든 파일 목록 출력");
            foreach (var file in di.GetFiles())
            {
                Console.WriteLine($"{file}");
            }
        }
    }
}


텍스트 데이터를 컬렉션 데이터로 가져오기

using System;
using System.IO;

namespace Dotnet
{
    public class Record
    {
        public string Name { get; set; }
        public string PhoneNumber { get; set; }
        public DateTime BirthDate { get; set; }
        public string AuthCode { get; set; }
    }

    class TextToCollection
    {
        static void Main()
        {
            // 텍스트 파일 읽기
            string[] lines =
                System.IO.File.ReadAllLines(
                    @"C:\Temp\src.txt", System.Text.Encoding.Default
                );
            foreach (var line in lines)
            {
                Console.WriteLine(line);
            }

            // 문자열 배열 정보를 컬렉션 형태의 개체에 담기
            List<Record> records = new List<Record>();
            foreach (var line in lines)
            {
                string[] splitData = line.Split(',');
                records.Add(
                    new Record
                    {
                        Name = splitData[0],
                        PhoneNumber=splitData[1],
                        BirthDate=Convert.ToDateTime(splitData[2]),
                        AuthCode=splitData[3]
                    });
            }

            // 데이터 하나만 출력하기
            Console.WriteLine(records[0]?.Name ?? "데이터가 없습니다.");
        }
    }
}

구분자로 콤마를 사용하는 텍스트 파일의 데이터를 읽어 List<T> 형태의 C# 컬렉션으로 변환

1처럼 파일 내용을 File.ReadAllLines() 메서드로 읽은 데이터를 2에서 List<Record> 형태의 리스트에 담는 작업을 보여줌


728x90
반응형