본문 바로가기

.NET/C#

C# File Input/Output

728x90
반응형

이제 정말 제가 어려워 하는 쪽으로 한발한발 다가서고 있네요

잘 모르는것을 공부하면서 포스트에 하나하나 옮기는 것이기 때문에 내용은 상당히 허접할 수 밖에 없다는 것을 이해해 주시길 바라고요~그럼 힘차게 다시 나아가보겠습니다~

I/O는 하드웨어의 디스켓이나 Usb 기타 저장장소에 데이터를 저장 또는 출력해주는 역할을 하고 있습니다.

보통 stream을 통해 하드웨어에 접근할 수 있죠, stream은 byte[]로 정의되어 있어 byte[]를 통해서 접근해야 되는 것입니다.

I/O 처리시 객체와 문자열(text)로 구성되는데요
겍체는 binary 데이터로 읽고 쓰는 형식이 달라서 쓰여진 형식으로만 읽을 수 있는 데이터를 말합니다. text 데이터는 항상 읽고 쓸수 있는 데이터를 말하고 있지요~

파일을 입출력할 경우도 객체와 텍스트로 나뉘는데요 여기서는 조금 변하는 점이 text 데이터는 char[], stream 에서는 byte[]로 변환이 이루어져야 하는데 stream에는 Reader/Writer가 있어 알아서 변환을 일으켜준답니다.
객체의 경우는 formatter가 변환을 해주게 됩니다~
BinaryFormatter : 개체나 연결된 개체의 전체 그래프를 이진 형식으로 serialize 및 deserialize 합니다.
SoapFormatter : 개체나 열결된 개체의 전체 그래프를 SOAP 형식으로 serialize 및 deserialize 합니다.
XmlSerializerFormatter
Serialization
Deserialization

formatter의 종류는 저정도 있다는것만 아시면 될꺼같습니다.
그리고 내장형 타입의경우는 binaryWriter를 통해 변환합니다~

아 여기까지만 쓰는데도 아주 미칠꺼 같은 느낌이네요. 당체 serialize가 파일 입출력시 쉽게 해준다는거 빼고는 잘 모르겠다는거죠...이걸 안해주면 안되게 될때도 있고...나원 ㅜㅜ 암튼 파일 입출력의 대충의 이해는 다음과 같았습니다. 제가 알고 있는 약간의 지식(?)으로 테스트 코드를 한번 만들어 보죠. 근데 위에 내용 이해 가나요?? 전 제가 쓰면서도 뭘 쓴건지 ㅜㅜ 참고로 MSDN 약간 참고 했습니다~

    1 static void Main(string[] args)

    2 {

    3     FileStream wstream = new FileStream("test1.txt", FileMode.Create, FileAccess.Write, FileShare.None);

    4 

    5     byte[] buffer = null;

    6     buffer = Encoding.UTF8.GetBytes("파일에 기록되는 데이터...1\n");

    7     wstream.Write(buffer, 0, buffer.Length);

    8 

    9     buffer = Encoding.UTF8.GetBytes("파일에 기록되는 데이터...2\n");

   10     wstream.Write(buffer, 0, buffer.Length);

   11 

   12     buffer = Encoding.UTF8.GetBytes("파일에 기록되는 데이터...3\n");

   13     wstream.Write(buffer, 0, buffer.Length);

   14 

   15     wstream.Close();

   16     Console.WriteLine("파일에 데이터를 썼습니다.");

   17 

   18     FileStream rstream = new FileStream("test1.txt", FileMode.Open, FileAccess.Read, FileShare.None);

   19 

   20     byte[] rbuffer = new byte[1024];

   21     int count = rstream.Read(rbuffer, 0, rbuffer.Length);

   22 

   23     string data = Encoding.UTF8.GetString(rbuffer, 0, count);

   24 

   25     rstream.Close();

   26 

   27     Console.WriteLine(data);

   28 }

다음과 같이 작성하였습니다.

3번째 줄의 FileStream 객체 생성하는 부분을 보면 첫번째인수는 해당 파일 명입니다. 두번째는 파일의 사용 방법인데요 create는 파일을 생성하겠다는 의미입니다. 이 때 같은 파일이 있다면 그냥 닥덮어쓰기 진행되니 조심하시길 바랍니다 ^^;; 세번째인수는 파일 접근에 대한 내용인데 Read, Write, ReadWrite의 종류가 있습니다. 딱 봐도 어떤 역할인지 알겠지요. 저기서는 파일 생성을 해야되니 ReadWrite, Write를 써야만 했습니다.  네번째인수는 파일을 공유할 것인지를 나타내는 인수로써 지금은 안하는걸로 해놓은거죠.

buffer에 텍스트 데이터를 저장시키고 wstream.Write를 하여 그 데이터를 test1.txt에 집어 넣는 과정이 15줄부터 23줄까지 나타나고 있습니다. 요주의는 파일스트림을 사용하였다면 꼭 닫아줘야 한다는겁니다. 안그러면 메모리의 효율적 사용이 힘들어지게 때문에 꼭 명심하셔야 됩니다.

28줄에서 다시 파일스트림 객체를 생성하는데 이때는 파일을 열고 읽는 목적으로 생성하고 있지요. 그 데이터를 data필드에 저장하고 출력하는 것입니다. 실행하면 결과는 다음과 같습니다.
그리고 해당 폴더에 보면 test1.txt 파일이 생성된 것을 볼수 있습니다.

저 파일을 열면 정확히 텍스트가 써져 있는것을 볼 수 있으실 겁니다~
위에서는 Text Data를 stream으로 변화시켜서 파일에 써 놓는것을 보았습니다.
이번에는 Text Data를 StreamReader/StreamWriter로 변환하는 것을 보도록 하겠습니다.

    1 static void Main(string[] args)

    2 {

    3     FileStream wstream = new FileStream("test2.txt", FileMode.Create);

    4     StreamWriter writer = new StreamWriter(wstream, Encoding.UTF8);

    5 

    6     writer.WriteLine("파일에 기록되는 데이터");

    7     writer.WriteLine("오늘은 " + DateTime.Now + "입니다.");

    8     writer.WriteLine("여기까지...");

    9     writer.Close();

   10     wstream.Close();

   11     Console.WriteLine("파일에 데이터를 썼습니다.");

   12 

   13     FileStream rsteam = new FileStream("test2.txt", FileMode.Open);

   14     StreamReader reader = new StreamReader(rsteam, Encoding.UTF8);

   15 

   16     string data = reader.ReadToEnd();

   17     Console.WriteLine(data);

   18     reader.Close();

   19     rsteam.Close();

   20 }
이번에는 보시는 것과 같이 StreamWriter와 StreamReader를 사용하고 있는데요. 어짜피 파일을 읽고 써야 되기 때문에 FileStream을 써야되는 것을 볼수가 있습니다.  4번째 줄에서 객체 생성시 첫번째 인수는 쓸 스트림을 나타내고 두번째인수는 쓸 사용할 문자 인코딩을 나타내고 있습니다. 그냥 stream을 이용한 것과 다른 점이라면 번거롭게 byte로 받아 넘기는 일을 하지 않아도 자동으로 해준다는 것입니다. 이것도 마찮가지로 위에서와 같은 결과를 내주고 있습니다. 파일또한 생성 되지요.
이번에는 primitive data를 binaryReader, binaryWriter로 변경하여 만들고 읽는 것을 확인해 보죠.

    1 static void Main(string[] args)

    2 {

    3     FileStream wstream = new FileStream("test3.dat", FileMode.Create);

    4     BinaryWriter writer = new BinaryWriter(wstream);

    5     for (int i = 0; i < 10000; i++)

    6         writer.Write(int.MaxValue);

    7 

    8     writer.Close();

    9     wstream.Close();

   10 

   11     FileStream rstream = new FileStream("test3.dat", FileMode.Open);

   12     BinaryReader reader = new BinaryReader(rstream);

   13     for (int i = 0; i < 10; i++)

   14         Console.WriteLine(reader.ReadInt32());

   15 

   16     reader.Close();

   17     rstream.Close();

   18 }

이번에도 많이 달라진 것은 없습니다만 바이너리로 저장하고 읽어온다는 것을 볼 수 있지요. 만약 저장은 바이너리로 저장하고 읽어올때는 StreamWriter 로 불러온다면 제대로 출력되지 않는 것을 볼수 있지요. 혹시 의심 된다면 한번 해보세요 ㅎㅎ


이제 객체를 파일로 쓸때를 보도록 하겠습니다.
이때는 위에서 말한것과 같이 Formatter를 사용하게 되죠. 보통 일반적인 파일를 쓸때는 BinaryFormatter를 사용하게 됩니다.

    1 [Serializable]//Attribute : 대상의 특성, 처리방식 등을 지정

    2 class TheObject

    3 {

    4     public int Number { get; set; }

    5     public string Name { get; set; }

    6 

    7     public override string ToString()

    8     {

    9         return string.Format("{0}, [{1}]", Number, Name);

   10     }

   11 }

다음과 같이 class를 선언해줍니다.
[Serializable]은 해당 클래스가 Serialize 하게 해주는 속성이라고 생각하면 됩니다.
클래스가 Serialize하게 하고 싶다면 저거만 붙이면 되는 것이죠 ^ㅡ^

    1 static void Main(string[] args)

    2 {

    3     TheObject obj = new TheObject

    4     {

    5         Number=1,

    6         Name="Test Data"

    7     };

    8 

    9     BinaryFormatter formatter = new BinaryFormatter();

   10 

   11     FileStream wstream = new FileStream("test4.dat", FileMode.Create);

   12     formatter.Serialize(wstream, obj);

   13     wstream.Close();

   14     Console.WriteLine("파일에 데이터를 썼습니다.");

   15 

   16     FileStream rstream = new FileStream("test4.dat", FileMode.Open);

   17     TheObject obj2 = formatter.Deserialize(rstream) as TheObject;

   18     rstream.Close();

   19     Console.WriteLine(obj2);

   20 }

12에서 Serialize를 통해 변환을 하고 파일에 쓰고 있는 겁니다. 그리고 Deserialize해서 다시 TheObject 형으로 변환해서 출력해주는 것이고요.

우선 기본적인 파일 인/아웃풋에 대해서 알아 보았습니다.
근데 여기서 하나 집고 넘어가야 할게 있을것으로 보여집니다.
아까부터 계속 Serialize/Deserialize라고 하는데 이게 뭔데 그러는거야?? 뭐야뭐야?? 이로고 계신분들 분명 계실꺼라고 생각합니다. 물론 저도 상당히 이해 안가는 부분이었는데요 잠깐 짧은 지식과 여기 저기 참고한 내용으로 설명을 드리고 마치도록 하겠습니다 ^^

우선 Serialize는 직렬화입니다. 원리는 데이터 구조를 바이트의 순열로 바꾸는 과정을 나타내는 것이지요. 이렇게 만들어진 바이트 스트림을 어떻게 표시하는지 나타내는 방법은 첨에 말한 Formatter들이라고 할 수 있고요.

직렬화는 결국 해당 필요한 형태로 변경할 수 있도록 도와주는 것입니다.(너무 어렵네요 ㅜㅜ)

아 머리아프고 힘들고 그러네요 ㅎㅎ

뭐 솔직히 이글을 보고 100% 이해하신 분은 이미 다 이해하시고 이글을 보신분들이라 생각합니다. 저도 다시공부하면서 글을쓰니 100%는 아니더라도 90%는 이해하게 된것 같고요~ㅎㅎ

이걸로 만족을하고 이만 글을 줄여야 될것 같습니다~

아...오늘은 크리스마스 이브인데요 모드 해피 성탄 되셨으면 합니다

메리크리스마스 ^ㅡ^

감사합니다~~

728x90
반응형

'.NET > C#' 카테고리의 다른 글

Thread 란?  (0) 2010.10.10
Windows Forms의 시작  (2) 2010.01.19
C# Event  (0) 2010.01.18
C# delegate  (0) 2010.01.14
FileAndDirectory  (0) 2010.01.12
C# Collection  (0) 2009.12.21
Interface  (0) 2009.12.18
Class(5)  (0) 2009.12.18
형변환에 대해서...  (0) 2009.12.18
System.Object 클래스 상속  (3) 2009.12.18