[C#] 텍스트 파일 입출력 (File, FileStream, StreamWriter/Reader)

Learning 

When: 1학년 12월 01일

 

How:  

학교 수행평가에 파일을 읽고 출력하는 방법에 관한 내용이 나올 예정이기 때문에 복습 겸 공부하게 되었습니다.

 

Understanding:

File

  • 간단 설명:  C#에서 파일을 입출력하는 방법은 다양하겠지만, 수행평가 범위인 File과 Stream을 이용하여 파일 입출력에 대해 설명해 보겠습니다. 일단 C#에는 컴퓨터의 주소와 값으로 파일을 저장하고, 주소로 파일을 읽을 수 있습니다. 제목에도 나와 있듯 저는 텍스트 파일만 다룰 것인데, 텍스트는 String을 통해 쉽게 다룰 수 있기 때문에 난이도가 어렵지는 않지만 외워야 할 부분들이 많아 정보를 정리하는 방식으로 설명해 보겠습니다. 일단 컴퓨터의 아무 파일이나 찾고 상단을 보면 그 파일이 내 PC에서부터 시작하여 어디로 이동해야 하는지 알 수 있습니다. C#에선 파일 관련 작업을 할 때 File 클래스를 사용하는데, 아까 말했듯 주소만 있다면 값을 저장하거나 불러올 수 있기 때문에 이 주소로 많은 것을 할 수 있습니다.
  • Write
File.WriteAllBytes("주소", byte[] 값); byte[] 타입의 값을 덮어씁니다. 주소 맨 끝에 값을 저장할 txt 파일을 쓰면 됩니다. 값 그대로 덮어쓰기 되어 저장됩니다. 
File.WriteAllLines("주소", string[] 값); string[] 타입의 값을 덮어씁니다. 주소 맨 끝에 저장할 txt 파일을 쓰면 이 함수는 특별하게 string 문자열 하나를 저장할 때마다 줄 바꿈을 하여 저장합니다.
File.WriteAllTexts("주소", string 값); string 타입의 값을 덮어씁니다. 위의 Write와 같이 문자열을 저장합니다.
  • Read
File.ReadAllBytes("주소"); 주소의 파일에 있는 값을 byte[] 타입으로 반환합니다.
File.Read AllLines("주소"); 주소의 파일에 있는 값을 string[] 타입으로 반환합니다.
File.Read AllTexts("주소"); 주소의 파일에 있는 값을 string 타입으로 반환합니다.
  • Append
File.AppendAllLines("주소", string[] 값) WriteAllLines와 비슷하지만, 값을 덮어쓰는 것이 아닌 뒤에 추가한다는 차이점이 있습니다.
File.AppendAllTexts("주소", string 값) AppendAllLines와 같이 string 문자열을 원래의 값 뒤에 추가합니다.

FileStream

  • 간단 설명: 지금은 크기가 작은 텍스트 파일만 사용했지만, 파일은 메가 바이트에서 기가 바이트까지 다양한 크기로 존재합니다. 그리고 프로그램을 실행할 때 사용할 수 있는 메모리 용량은 램의 크기가 결정하는데, 동영상 같은 커다란 파일을 읽어서 변수에 저장하거나 커다란 값을 저장할 때는 요즘같이 16, 32기가 램을 사용하더라도 무리가 갈 수 있고, 보통 프로그램을 여러 개 켜고 있어서 각각의 프로그램이 램에 값을 저장하고 있다면 램의 크기를 초과하는 것도 충분히 가능한 상황이 됩니다. 그래서 이런 상황을 방지하기 위해 파일을 한 번에 읽고 쓰는 것이 아닌, 조금씩 읽고 쓰기 위해 FileStream(파일 흐름)으로 개울에 물이 흐르듯이 값을 조금씩 흘려보내는 방식으로 파일 입출력을 하는 방법을 사용합니다. FileStream도 File을 사용하긴 해야 하는데, File 대신 FileStream이라는 클래스 타입의 변수에 File.Open() 메서드의 반환 값인 FileStream 객체를 할당하여 사용할 수 있습니다. 하지만 FileStream도 값을 읽고 쓸 때 byte 단위를 주로 사용하여 귀찮게 문자도 형변환을 해주어야 한다는 단점이 있습니다. 그래서 StreamReader, StreamWriter 클래스로 읽고 쓰는 것을 주로 사용하게 됩니다. 그리고 FileStream이나 StreamRead,Write는 파일을 어떻게 사용할 것인지 매개 변수를 통하여 명시해 주어야 합니다. 예를 들어 읽기 전용, 쓰기 가능 등의 사용 목적이 있습니다.
FileStream fileStream = File.Open("주소", FileMode); FileMode에는 다음과 같은 값이 있습니다.
fileStream.WrtieByte(byte 값) byte 값(문자 하나)을 씁니다. 쓴 후에는 키보드의 오른쪽 화살표 버튼을 누른 것처럼 다음에 읽거나 쓸 스트림 커서의 위치를 한 칸 옮깁니다. 
fileStream.ReadByte(byte 값) byte 값(문자 하나)을 읽습니다. 쓴 후에는 키보드의 오른쪽 화살표 버튼을 누른 것처럼 다음에 읽거나 쓸 스트림 커서의 위치를 한 칸 옮깁니다. 
  • Append: 파일이 없다면 만들고 있다면 그 파일의 뒤부터 값을 추가할 수 있습니다.
  • Create: 파일이 있다면 덮어쓰고 없다면 파일을 새로 만듭니다.
  •  CreateNew: 파일을 새로 만듭니다. 파일이 이미 있다면 에러를 발생시킵니다.
  • Open: 파일이 있다면 열고, 없다면 예외를 발생시킵니다.
  • OpenOrCreate: 파일이 있다면 열고 없다면 만듭니다. Appnd와 달리 읽기가 가능합니다.
  • Truncate: 파일이 있다면 열고, 내용을 전부 0 바이트가 되도록 자릅니다. 파일 자체는 유지됩니다.

StreamReader, StreamWriter

  • 간단 설명: FileStream의 불편함을 해소하기 위해 만들어졌지만, 문제를 하나 해결하니 다른 문제가 생겼는데, C++처럼 만든 객체를 직접 Close() 해주어야 한다는 것입니다. 이에 끝나지 않고 이마저도 해결할 방법이 있는데, using을 사용하는 것입니다. using을 사용하는 방법은 2가지가 있는데, using 뒤에 ()와 같은 괄호를 추가하고 그 괄호 안에서 변수에 StreamWriter, StreamReader를 생성, 괄호 뒤에 {}와 같은 중괄호를 추가하여 그 중괄호 안에서 객체를 활용하면 중괄호가 끝났을 때 자동으로 Close() 함수를 실행시켜 줍니다. (정확히 말하면 IDisposable 인터페이스의 Dispose() 메서드를 실행시키는 것인데, Close() 메서드가 Dispose() 메서드를 실행시키는 메서드이기에 큰 차이는 없습니다.) 나머지 방법은 using을 키워드로 사용하는 것인데, 변수의 타입 왼쪽에 using 키워드를 붙이면 방금 말한 코드 블록을 직접 만들지 않게 되고, 자동으로 Dispose() 메서드를 실행시켜 주는 코드 블록의 범위가 그 변수가 선언된 메서드의 코드 블록으로 확장됩니다. 이것까지가 Close() 메서드에 대한 설명이었고, StreamReader, StreamWriter의 메서드는 Console처럼 다양한 타입을 지원해 주는 메서드가 있습니다.
StreamReader streamReader = new StreamReader(File.Open("주소", FileMode); File.Open 메서드로 열고 반환된 FileStream 객체를 받으면 그 객체를 StreamReader의 생성자의 인수로 사용하여 StreamReader 객체를 만들 수 있습니다.
streamReader.ReadLine() 스트림 커서가 있는 한 줄의 끝을 커서의 위치부터 읽어 string 형식으로 반환합니다.
streamReader.ReadToEnd() 스트림 커서가 있는 위치부터 파일의 끝까지 읽어 전부 반환합니다.
StreamWriter streamWriter = new StreamWriter(File.Open("주소", FileMode);  File.Open 메서드로 열고 반환된 FileStream 객체를 받으면 그 객체를 StreamWriter의 생성자의 인수로 사용하여 StreamWriter객체를 만들 수 있습니다.
streamWriter.WriteLine(값) 스트림 커서가 있는 곳부터 값을 적고 줄 바꿉니다. int, float 등 다양한 형식을 지원합니다.
streamWriter.Write(값) 스트림 커서가 있는 곳부터 값을 적습니다. WriteLine처럼 다양한 형식을 지원합니다.

 

 

Result: 파일 입출력이 깊이 파기엔 좀 어려울 것 같고 얕게 공부하기엔 메서드 외우기와 약간의 개념만 공부하게 되어서 애매한 것 같습니다. 시간이 된다면 작동 방식 등 자세한 내용을 정리해 보겠습니다.

'공부 > C#' 카테고리의 다른 글

[C#] 박싱(Boxing)과 언박싱(Unboxing)  (0) 2025.10.20
[C#] 죽음의 다이아몬드에 대한 개인적인 생각 (반박 환영)  (0) 2025.09.12
[C#] Obscuring  (0) 2025.09.08
[C#] Hiding  (3) 2025.09.07
[C#] Shadoing  (0) 2025.09.06