C# 파일 입출력 마스터하기: 스트림, 읽기/쓰기, 고급 파일 작업
파일(File)은 특정 이름과 디렉터리 경로를 가진 디스크에 저장된 데이터 모음입니다. 파일을 읽기/쓰기 위해 열면 스트림(Stream)이 됩니다.
스트림은 통신 경로를 통과하는 바이트 시퀀스입니다. 두 주요 스트림:
- 입력 스트림(Input Stream): 파일에서 데이터 읽기 (읽기 작업)
- 출력 스트림(Output Stream): 파일에 데이터 쓰기 (쓰기 작업)
C# I/O 클래스 (System.IO 네임스페이스)
파일 생성/삭제, 읽기/쓰기, 닫기 등 다양한 파일 작업을 위한 클래스들:
| 번호 | I/O 클래스 및 설명 |
| 1 | BinaryReader - 이진 스트림에서 기본 데이터 읽기 |
| 2 | BinaryWriter - 기본 데이터를 이진 형식으로 쓰기 |
| 3 | BufferedStream - 바이트 스트림 임시 저장소 |
| 4 | Directory - 디렉터리 구조 조작 |
| 5 | DirectoryInfo - 디렉터리 작업 수행 |
| 6 | DriveInfo - 드라이브 정보 제공 |
| 7 | File - 파일 조작 (정적 메서드) |
| 8 | FileInfo - 파일 작업 수행 (인스턴스 메서드) |
| 9 | FileStream - 파일의 임의 위치 읽기/쓰기 |
| 10 | MemoryStream - 메모리에 저장된 스트림 데이터 랜덤 액세스 |
| 11 | Path - 경로 정보 조작 |
| 12 | StreamReader - 바이트 스트림에서 문자 읽기 |
| 13 | StreamWriter - 스트림에 문자 쓰기 |
| 14 | StringReader - 문자열 버퍼에서 읽기 |
| 15 | StringWriter - 문자열 버퍼에 쓰기 |
FileStream 클래스
FileStream은 System.IO 네임스페이스의 클래스로, 파일 읽기/쓰기/닫기를 돕습니다. 추상 클래스 Stream에서 파생됩니다.
FileStream 객체 생성
FileStream 객체이름 = new FileStream(
파일_이름,
FileMode 열거자,
FileAccess 열거자,
FileShare 열거자
);
예: sample.txt 읽기용 FileStream 생성
FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
FileMode 열거자 멤버
| 멤버 | 설명 |
Append | 기존 파일 열기 후 커서를 끝으로, 없으면 생성 |
Create | 새 파일 생성 (기존 파일 덮어씀) |
CreateNew | 새 파일 생성 (기존 파일 있으면 예외) |
Open | 기존 파일 열기 (없으면 예외) |
OpenOrCreate | 있으면 열기, 없으면 생성 |
Truncate | 기존 파일 열기 후 크기를 0으로 |
FileAccess 열거자
Read, ReadWrite, Write
FileShare 열거자
| 멤버 | 설명 |
Inheritable | 파일 핸들 상속 허용 |
None | 공유 거부 |
Read | 읽기 공유 허용 |
ReadWrite | 읽기/쓰기 공유 허용 |
Write | 쓰기 공유 허용 |
FileStream 사용 예제
using System;
using System.IO;
namespace FileIOApplication
{
class Program
{
static void Main(string[] args)
{
// 파일 생성/열기 (읽기/쓰기)
FileStream F = new FileStream("test.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite);
// 바이트 쓰기 (1~20)
for (int i = 1; i <= 20; i++)
{
F.WriteByte((byte)i);
}
// 처음으로 이동 후 읽기
F.Position = 0;
for (int i = 0; i <= 20; i++)
{
Console.Write(F.ReadByte() + " ");
}
F.Close();
Console.ReadKey();
}
}
}
출력: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1
-1은 스트림 끝(EOF)을 의미합니다.
고급 파일 작업
| 번호 | 주제 및 설명 |
| 1 | 텍스트 파일 읽기/쓰기
StreamReader, StreamWriter 클래스 활용 |
| 2 | 이진 파일 읽기/쓰기
BinaryReader, BinaryWriter 클래스 활용 |
| 3 | Windows 파일 시스템 조작 파일/디렉터리 탐색, 위치 찾기 |
텍스트 파일 읽기/쓰기 (StreamReader/StreamWriter)
// 쓰기
using (StreamWriter sw = new StreamWriter("output.txt"))
{
sw.WriteLine("첫 번째 줄");
sw.WriteLine("두 번째 줄");
sw.Write("세 번째 줄 ");
sw.Write("이어쓰기");
}
// 읽기
using (StreamReader sr = new StreamReader("output.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
// 전체 읽기
string allText = File.ReadAllText("output.txt"); // 정적 메서드 편의 기능
string[] lines = File.ReadAllLines("output.txt");
이진 파일 읽기/쓰기 (BinaryReader/BinaryWriter)
// 쓰기
using (BinaryWriter bw = new BinaryWriter(File.Open("data.bin", FileMode.Create)))
{
bw.Write(123); // int
bw.Write(3.14); // double
bw.Write("Hello"); // string
bw.Write(true); // bool
}
// 읽기 (쓰기 순서와 동일해야 함)
using (BinaryReader br = new BinaryReader(File.Open("data.bin", FileMode.Open)))
{
int i = br.ReadInt32();
double d = br.ReadDouble();
string s = br.ReadString();
bool b = br.ReadBoolean();
}
파일/디렉터리 조작 (File, Directory, FileInfo, DirectoryInfo)
// File 클래스 (정적 메서드)
File.Exists("test.txt");
File.Copy("source.txt", "dest.txt", true); // 덮어쓰기
File.Move("old.txt", "new.txt");
File.Delete("temp.txt");
File.GetCreationTime("test.txt");
// FileInfo 클래스 (인스턴스 메서드)
FileInfo fi = new FileInfo("test.txt");
long size = fi.Length;
DateTime created = fi.CreationTime;
fi.CopyTo("backup.txt");
fi.Delete();
// Directory 클래스
Directory.CreateDirectory(@"C:\MyApp\Data");
string[] files = Directory.GetFiles(@"C:\MyApp\Data", "*.txt");
string[] dirs = Directory.GetDirectories(@"C:\MyApp\Data");
Directory.Delete(@"C:\MyApp\Data", true); // 하위 포함 삭제
// Path 클래스 (경로 조작)
string fullPath = Path.Combine(@"C:\Data", "file.txt");
string fileName = Path.GetFileName(fullPath);
string dirName = Path.GetDirectoryName(fullPath);
string ext = Path.GetExtension(fullPath);
string noExt = Path.GetFileNameWithoutExtension(fullPath);
string tempPath = Path.GetTempFileName();
모범 사례
- using 문 필수:
IDisposable 구현 스트림은 using 블록으로 자동 해제
- 인코딩 명시:
new StreamWriter(path, false, Encoding.UTF8)
- 비동기 I/O 활용: 대용량 파일 시
ReadAsync, WriteAsync, CopyToAsync 사용
- 예외 처리:
IOException, UnauthorizedAccessException, FileNotFoundException 등 구체적 예외 잡기
- 경로 결합은 Path.Combine: 문자열 연결 대신 사용 (플랫폼 독립적)
핵심: 텍스트 처리는 StreamReader/Writer, 이진 데이터는 BinaryReader/Writer, 간편 작업은 File 정적 메서드, 상태 유지가 필요하면 FileInfo/DirectoryInfo를 사용하세요.