[C# 교과서] 58. 스트림과 파일 입출력 맛보기
프로그램 코드에서 작성된 데이터는 목적에 따라 영구적으로 보관해야 할 때가 있음
이 때는 파일이나 데이터베이스에 저장
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";
파일과 디렉터리 관련 클래스
파일을 생성하고 삭제하는 일반적인 절차는 다음과 같음
- StreamWriter 클래스를 사용하여 텍스트 파일 쓰기
- StreamReader 클래스를 사용하여 텍스트 파일 읽기
- File과 FileInfo 클래스로 파일 정보 얻기
- 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> 형태의 리스트에 담는 작업을 보여줌