본문 바로가기

C#/파일 처리

C#에서 텍스트 파일 쓰기 (파일 출력)

1. 텍스트 파일에 한 행씩 문자열을 쓰는 방법

 

System.IO 네임스페이스에 있는 StreamWriter 클래스를 사용하면 텍스트를 파일에 출력할 수 있다.

//텍스트 파일에 한 행씩 문자열을 출력한다
var filePath = @"C:\Example.txt";
using (var writer = new SteamWriter(filePath))
{
    writer.WriteLine(“example 1”);
    writer.WriteLine(“example 2”);
    writer.WriteLine(“example 3”);
    writer.WriteLine(“example 4”);
}

 

StreamWriter의 생성자에서 파일 경로를 지정

문자 인코드는 기본 문자코드(UTF-8)가 지정된 것으로 간주된다.

생성자가 호출될 때 파일이 존재하지 않으면 새 파일이 생성된다.

이미 파일이 존재할 경우에는 파일이 덮어쓰기 모드로 열린다.

 

행을 출력하려면 WriteLine 메서드를 사용한다.

인수에 넘겨준 문자열 끝에 줄바꿈 문자가 붙은 후에 파일에 출력된다.

 

 

2. 기존에 있는 텍스트 파일 끝에 행을 추가하는 방법

 

기존 파일 끝에 행을 추가하려면 StreamWriter 생성자의 두 번째 인수인 append 플래그에 true를 지정한다.

false를 지정하면 덮어쓰기 모드가 된다.

파일이 존재하지 않으면 새 파일이 생성된다.

var lines = new[] { “================”, “example 5”, “example 6”, };
var filePath = @"C:\Example.txt";
//C# 4.0 이후 버전부터 사용할 수 있는 명명된 인수를 사용
//이렇게 하면 true가 무엇을 의미하는지 쉽게 알 수 있어 주석을 추가할 필요가 없어진다.
using (var writer = new StreamWriter(filePath, append: true))
{
    foreach (var line in lines)
        writer.WriteLine(line);
}

 

 

3. 문자열 배열을 한번에 파일에 출력하는 방법

 

배열에 저장된 문자열을 한번에 출력하려면 File 클래스에 있는 WriteAllLines라는 정적 메서드를 이용하는 것이 편리하다.

var lines = new[] { “sword”, “spear”, “bow”, “shield”, };
var filePath = @"C:\Example.txt";
File.WriteAllLines(filePath, lines);

var items = new List<string> { “sword”, “spear”, “bow”, “shield”, };
var filePath = @"C:\Example.txt";
//문자열의 길이가 4문자보다 긴 것만 파일에 출력
File.WriteAllLines(filePath, items.Where(s => s.Length > 4));

 

행을 파일 끝에 추가할 때는 AppendAllLines라는 정적 메서드를 사용하면 된다.

 

 

4. 기존에 있는 텍스트 파일의 첫머리에 행을 삽입하는 방법

 

파일의 첫머리에 행을 삽입하는 기능이 StreamWriter 클래스에는 존재하지 않는다.

var filePath = @"C:\Example.txt";
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
    using (var reader = new StreamReader(stream))
    using (var writer = new StreamWriter(stream))
    {
        string texts = reader.ReadToEnd();
        stream.Position = 0;
        writer.WriteLine(“New example1”);
        writer.WriteLine(“New example2”);
        writer.Write(texts);
    }
}

 

1) FileStream 클래스를 사용해 텍스트 파일을 엽니다. FileStream 생성자의 인수는 다음과 같다.

 

 - FileMode.Open: 기존 파일을 연다

 - FileAccess.ReadWrite : 읽기/쓰기가 가능하게 한다

 - FileShare.None : 다른 프로세스가 이 파일에 접근하지 못하게 한다

 

2) 1)에서 구한 stream 객체를 인수로 사용해 StreamReader와 StreamWriter 객체를 생성한다.

 

3) ReadToEnd 메서드로 한꺼번에 모든 행을 읽어 들인다. ReadAllLines 메서드와 달리 반환값의 형은 string 형이다. texts 변수에 모든 행을 읽어 들입니다. 줄바꿈 코드도 그대로 읽어 들인다.

 

4) 파일을 마지막까지 읽었으므로 파일 안에 있는 포지션은 파일 끝을 가리키고 있다. 그래서 FileStream 클래스에 있는 Position 속성0을 대입해 포지션을 첫머리로 바꿔준다.

 

5) WriteLine 메서드를 통해 행을 출력한다. 포지션을 파일의 첫머리로 되돌려 놓았으므로 텍스트 파일 첫머리에 출력된다.

 

6) 3)에서 읽어 들인 모든 텍스트를 Write 메서드를 통해 한꺼번에 써넣는다. 결과적으로 5)에서 출력한 행이 삽입된다.

 

7) using 문에서 빠져나와 FileStream을 닫는다.

 

 

////////////////////////////////////////////// 나쁜 예시 //////////////////////////////////////////////////

var filePath = @"C:\Example.txt";
string texts = “”;
//파일을 모두 읽어 들인다
using (var reader = new StreamReader(filePath))
{
    texts = reader.ReadToEnd();
}
//일단 닫는다

<- 이 사이에 다른 프로세스/다른 스레드가 파일의 내용을 수정했을 가능성이 있다

//파일을 다시 열어서 출력처리를 실행한다
using (var writer = new StreamWriter(stream))
{
    writer.WriteLine(“New example1”);
    writer.WriteLine(“New example2”);
    writer.Write(texts);    <- 다른 프로세스/다른 스레드가 수정한 내용을 사라진다
}

 

위의 코드는 파일을 입력 전용으로 열고 모든 행을 읽어 들이고 나서 일단 파일을 닫고 파일을 다시 쓰기 전용으로 열어서 행을 삽입한다.

 

대부분의 경우에 이 방법이 통하지만 대상이 되는 파일에 여러 프로세스가 접근할 경우에는 닫기와 열기 작업 사이에 다른 프로세스가 파일의 내용을 수정했을 가능성이 있다.