본문 바로가기

문과 코린이의, [C#] 기록/C# 활용

[문과 코린이의 IT 기록장] C# 기초 예시 - XMLReader, XMLWriter

반응형

[문과 코린이의 IT 기록장] C# 기초 예시 - XMLReader, XMLWriter

[문과 코린이의 IT 기록장] C# 기초 예시 - XMLReader, XMLWriter 


0. C# _ XMLReader, XMLWriter에 대해서

[ 일반적인 프로그램 ]

- 프로그램을 할 때 일반적인 데이터 저장 순서 : 텍스트 -> XML -> DB

 * Stream의 경우 Log 형태로 많이 사용되지만, XML 형태는 프로그램을 시작할 때의 설정 값을 저장하는 용도로 많이 사용된다.

 

[ XML이란? ]

- XML(Extensible Markup Language) * 확장될 수 있는 표시 언어

- XML은 HTML과 매우 비슷한 문자 기반의 마크업 언어이며, 사람과 기계가 동시에 읽기 편한 구조로 되어있음.

- 그러나 XML은 HTML처럼 데이터를 보여주는 것이 목적이 아니라, 데이터를 저장하고 전달할 목적으로만 만들어짐.

- XML은 트리구조로 이루어져 있으며, root를 기준으로 자식 node를 파생시켜서 사용함.

 

 

XML File 예시 )

[ 이 예제는, StreamReader, StreaWrite와 코드 및 UI 부분이 유사합니다. ]

[문과 코린이의 IT 기록장] C# 기초 예시 - StreamReader, StreamWrite (tistory.com)


1. UI 부분

 


2. 코드 부분

1) CXML_Control 클래스

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Xml; // XmlReader 활용

 

namespace _20210626___StreamReader__StreamWrite

{

class CXML_Control

{

 public static string _TEXT_DATA = "TEXT_DATA" 

 public static string _CBOX_DATA = "CBOX_DATA"

 public static string _NUMBER_DATA = "NUMBER_DATA"

[ static ]
- 변수나 함수, 클래스에 정적 속성을 부여하는 것으로 클래스로부터 객체를 생성하지 않고 변수나 함수를 호출할 수 있도록 해주는 것
- 프로그램 시작부터 끝까지 잘 변하지 않는 함수값들에 대해 설정해놓는다.

# 인스턴스에는 정적 변수(static)이 포함되지 않으며, 일반 맴버 변수만 포함되고, 해당 정적 변수는 그 클래스가 처음 사용되는 시점에 별도의 메모리 공간에 할당된다. 따라서, 실제로 객체를 생성해 맴버 변수를 찾으면 목록에 나오지 않는다.

 

 

/// <summary>

/// 읽어오는부분

/// </summary>

/// <param name="strXMLPath"></param>

/// <returns></returns>

 

public Dictionary<string, string> fXML_Reader(string strXMLPath)

// 반환 형태 : Dictionary<string, string>

// 함수 이름 : fXML_Reader

// 매개변수 : strXMLPath , 매개변수 타입 : string

{

 Dictionary<string, string> DXMLConfing = new Dictionary<string, string>();

// Dictionary<string, string> 타입의, DXMLConfing 객체를 생성한다.

 

 using (XmlReader rd = XmlReader.Create(strXMLPath))

// strXMLPath를 사용한, XmlReader 타입의 rd객체를 생성한다.

[ using ]
- 해당 조건 범위를 벗어나면, 자동으로 Dispose된다.
- 즉 일일이 Close를 해주지 않아도 되기 때문에, 메모리 관리가 쉬워진다.
[ XmlReader ]
 * namespace : System.Xml
- 이 클래스는 xml을 순차적으로 한 노드씩 읽는다.

# XmlReader.Read() 메소드 : XML 파일의 첫 번째 노드를 읽은 다음 while 루프를 활용해 전체 파일을 읽는다.
# XmlReader.IsStartElement() 메소드 : 현재 콘텐츠 노드가, 시작 태그(요소)인지 테스트한다.
# XmlReader.ReadElementContentAsString() 메소드 : 현재 요소를 읽고 콘텐츠를 String 개체로 반환한다.

 {

   while (rd.Read()) // XML 파일의 첫 번째 노드를 읽은 후, 전체 파일을 순차적으로 읽는다.

   {

      if (rd.IsStartElement()) // 만약 rd 객체의 현재 콘텐츠 노드가, 시작 태그라면?

     {

       if (rd.Name.Equals("SETTING"))

        {

         string strID = rd["ID"];

         rd.Read();

 

         string strText = rd.ReadElementContentAsString(_TEXT_DATA,""); 

// rd 객체의 Key(_TEXT_DATA)와 일치하는 Value(값을 String 개체로 반환해, strText변수에 넣는다.

         DXMLConfing.Add(_TEXT_DATA, strText);

// Key : _TEXT_DATA, Value : strText -> Key로 Value를 찾을 수 있음

 * Containskey() 메소드를 활용해 찾고 싶은 Key를 입력하면, Dictionary에서 Key가 존재하는지 확인하고, 그 결과를 반환한다. 

 

         string strCbox = rd.ReadElementContentAsString(_CBOX_DATA, "");

         DXMLConfing.Add(_CBOX_DATA, strCbox);

 

         string strNumber = rd.ReadElementContentAsString(_NUMBER_DATA, "");

         DXMLConfing.Add(_NUMBER_DATA, strNumber);

       }

     }

   }

 } 

return DXMLConfing; // Dictionary <string, string> 타입 반환

}

 

 

 

/// <summary>

/// 저장하는부분 (XML 파일을 만드는 부분)

/// </summary>

/// <param name="strXMLPath"></param>

/// <param name="DXMLConfing"></param>

public void fXML_Writer(string strXMLPath, Dictionary<string, string> DXMLConfing)

// 반환 형태 : void

// 함수 이름 : fXML_Writer

// 매개변수 : string strXMLPath, Dictionary<string, string> DXMLConfing)

{

 using (XmlWriter wr = XmlWriter.Create(strXMLPath))

// strXMLPath를 사용한, XmlWriter 타입의 wr객체를 생성한다.

[ XmlWriter ]
 * namespace : System.Xml
- 이 클래스는 xml데이터가 포함된 스트림 또는 파일을 생성할 수 있도록, 빠르고 앞으로만 이동하고, 캐시되지 않은 방법을 제공하는 작성기를 나타낸다.

# XmlWriter.WriteStartDocument() 메서드 : 파생 클래스에서 재정의되면, 버전이 1.0인 XML 선언을 작성한다.
# XmlWriter.WriteStartElement(string) 메서드 : 파생 클래스에서 재정의되면, 지정된 로컬 이름을 사용하여 시작 태그를 작성한다.
# XmlWriter.WriteAttributeStarting(string, string) 메서드 : 파생 클래스에서 재정의되면, 지정된 로컬 이름 및 값이 있는 특성을 작성한다.
# XmlWriter.WriteElementString(string, string) 메서드 : 지정된 로컬 이름 및 값을 사용하여, 요소를 작성한다.
# XmlWriter.WriteEndElement() 메서드 : 파생 클래스에서 재정의되면, 한 요소를 닫고 해당 네임스페이스 범위를 팝한다.
# XmlWriter.WriteEndDocument() 메서드 : 파생 클래스에서 재정의되면, 열려 있는 모든 요소나 특성을 닫고 작성기를 다시 시작 상태로 설정한다.

 {

   wr.WriteStartDocument();

 

   // SETTING

   wr.WriteStartElement("SETTING");

   wr.WriteAttributeString("ID","0001");

 

   wr.WriteElementString(_TEXT_DATA, DXMLConfing[_TEXT_DATA]);

   wr.WriteElementString(_CBOX_DATA, DXMLConfing[_CBOX_DATA]);

   wr.WriteElementString(_NUMBER_DATA, DXMLConfing[_NUMBER_DATA]);

 

   wr.WriteEndElement();

   wr.WriteEndDocument();

 }

}

}

}

 


2) Form 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.IO; 

sing System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

 

namespace _20210626___StreamReader__StreamWrite

{

public partial class Form1 : Form

{

 

CXML_Control _XMLnew CXML_Control();

  // CXML_Control 형태의, _XML 객체를 만들어라.

Dictionary<string, string> _dData = new Dictionary<string, string>();

  // Dictionary<string, string>형태의, _dData 객체를 만들어라.

 

public Form1()

{

 InitializeComponent();

}

 

private void btnConfigSet_Click(object sender, EventArgs e) // Config 설정하기 버튼을 클릭했을 때

{

 string strText = tboxData.Text;

// tboxData 텍스트 박스의 Text 부분을, strText 변수에 넣는다.

 bool bChecked = cboxData.Checked;

// cboxData 체크 박스의 Checked 여부에 대해, bChecked 변수에 넣는다. (bool 타입)

 int iNumber = (int)numData.Value;

// numData NumbericUPDown의 값을 (int)형으로 변환시켜, iNumber 변수에 넣는다.

 

 StringBuilder sb = new StringBuilder(); // 위의 것들을 하나로 묶어주기 위해, Stringbuilder형 sb객체 생성

 string strEnter = "\r\n" // 개행을 위한 변수

 sb.Append(strText + "\r\n"); 

 sb.Append(bChecked.ToString() + strEnter);

 sb.Append(iNumber.ToString() + strEnter);

 

 tboxConfigData.Text = sb.ToString();

// 객체 sb를 String 형태로 변환해, tboxConfigData의 Text 부분에 표시한다.

 

 

 _dData.Clear(); // 전역으로 있는 값이기 때문에, 항상 초기화 시켜주기

// 프로그램 데이터에 따로 Dictionary 형태로, 정보를 지니고 있음. (눈에는 보이지 X)

 

/* Static 형태를 추가해 주는 것 (Static은 _dData객체 내부에 존재하지 않기 때문) */

 _dData.Add(CXML_Control._TEXT_DATA, strText);

// _dData 객체에 (key : CXML_Control._TEXT_DATA, value : strText) 추가

 _dData.Add(CXML_Control._CBOX_DATA, bChecked.ToString());

 _dData.Add(CXML_Control._NUMBER_DATA, iNumber.ToString());  

}

 

 

private void btnSave_Click(object sender, EventArgs e) // Text 저장하기 버튼을 눌렀을 때

{

 string strFilePath = string.Empty; // 저장할 때의 파일 경로 변수

 

 SFDialog.InitialDirectory = Application.StartupPath; // 다이얼로그가 Open 되었을 때, 최초의 경로 설정

 SFDialog.FileName = "*.xml" // 파일 이름

 SFDialog.Filter = "Xml files (*.xml)|*.xml|All files (*.*)|*.*" // 파일 형식

 SFDialog.ShowDialog();

 

 if (SFDialog.ShowDialog() == DialogResult.OK) // 만약 DialogResult가 OK(저장)이 된다면?

 {

   strFilePath = SFDialog.FileName; // SFDialog의 FileName을, strFilePath에 넣는다.

   _XML.fXML_Writer(strFilePath, _dData); 

   // _XML 객체의, fXML_Writer 함수 (string strXMLPath, Dictionary<string, string> DXMLConfing) 실행

 }

}

 

private void btnLoad_Click(object sender, EventArgs e) // Text 읽어오기 버튼을 클릭했을 때

{

 string strFilePath = string.Empty;  // 저장할 때의 파일 경로 변수

 OFDialog.InitialDirectory = Application.StartupPath; // 다이얼로그가 Open 되어 있을 때, 최초의 경로 설정

 OFDialog.FileName = "*.xml" // 파일 이름

 OFDialog.Filter = "Xml files (*.xml)|*.xml|All files (*.*)|*.*" // 파일 형식

 

 StringBuilder sb = new StringBuilder();

   

 if (OFDialog.ShowDialog() == DialogResult.OK) // 만약 DialogResult가 OK(열기) 된다면

 {

   strFilePath = OFDialog.FileName; // OFDialog의 FileName을, strFilePath에 가져온다.

   sb.Append(File.ReadAllText(strFilePath)); // 텍스트 파일을 String 형태로 한 번에 읽어와, sb객체에 저장한다.

   tboxConfigData.Text = sb.ToString(); // sb객체를 String으로 변환시켜, tboxConfigData의 Text부분에 출력한다.

 

   _dData.Clear(); // 초기화

   _dData = _XML.fXML_Reader(strFilePath); 

// _XML 객체의, fXML_Reader 함수(Dictionary<string, string> fXML_Reader(string strXMLPath)) 실행

// 이후 _dData 객체에 값 저장

 }

}

 

private void btnConfigRead_Click(object sender, EventArgs e) // Config 가져오기 버튼을 눌렀을 때

{

/* Dictionary(_dData)에 있는 정보를 UI에 입력한다. */

 tboxData.Text = _dData[CXML_Control._TEXT_DATA];

// _dData의 CXML_Control._TEXT_DATA와 연결된 값을 가져오거나 설정한 후, tboxData의 Text부분에 출력한다.

 cboxData.Checked = bool.Parse(_dData[CXML_Control._CBOX_DATA]);

// _dData의 CXML_Control._CBOX_DATA와 연결된 값을 가져오거나 설정한 후, bool 타입으로 변환시켜, cboxData의 Checked부분에 출력한다.

 numData.Value = int.Parse(_dData[CXML_Control._NUMBER_DATA]);

// _dData의 CXML_Control._NUMBER_DATA와 연결된 값을 가져오거나 설정한 후, int 타입으로 변환시켜, numData의 Value부분에 출력한다.

}

}

}

 


3. 결과물 부분


4.  C#기초 예시 / 참고 자료를 더 보고 싶다면?

 


* 유의사항
- 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다.
- 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다.
- 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :)
반응형