Form1.cs
using System;
using System.IO;
using System.Windows.Forms;
namespace PRAC_251024
{
public partial class Form1 : Form
{
// --- 전역 변수 선언 ---
// ini 파일 경로
string iniFilePath;
// 섹션 이름을 저장할 배열 (예: [A], [B], [C])
string[] sections;
// 각 섹션별 키의 값을 저장할 2차원 배열
// 예: values[섹션인덱스, 키인덱스] = "값"
string[,] values;
// 섹션 개수 (현재까지 몇 개의 섹션을 읽었는가)
int sectionCount = 0;
// 한 섹션당 키 개수 (예제에서는 3개: 1,2,3)
int keyCount = 3;
// --- 폼 생성자 ---
public Form1()
{
InitializeComponent();
// 트리뷰와 콤보박스는 수동으로 이벤트 연결
tv_INI.AfterSelect += Tv_INI_AfterSelect;
cb_Key.SelectedIndexChanged += Cb_Key_SelectedIndexChanged;
}
// --- ini 파일을 읽어서 배열에 저장하는 함수 ---
private void LoadIniFile(string path)
{
// ini 파일의 모든 줄을 배열로 읽어오기
string[] lines = File.ReadAllLines(path);
// 배열 초기화 (최대 10개의 섹션, 섹션당 최대 10개의 키를 가정)
sections = new string[10];
values = new string[10, 10];
sectionCount = 0;
string currentSection = ""; // 현재 섹션 이름
int keyIndex = 0; // 현재 섹션에서의 키 인덱스
// 한 줄씩 읽으면서 분석하기
foreach (string line in lines)
{
string trimmed = line.Trim(); // 앞뒤 공백 제거
if (string.IsNullOrEmpty(trimmed)) continue; // 빈 줄이면 건너뛰기
// [A] 같은 섹션명인지 확인
if (trimmed.StartsWith("[") && trimmed.EndsWith("]"))
{
// 대괄호 안의 섹션 이름 추출
currentSection = trimmed.Substring(1, trimmed.Length - 2);
// 섹션 배열에 저장
sections[sectionCount] = currentSection;
// 새로운 섹션이 시작되었으니 키 인덱스 초기화
keyIndex = 0;
// 섹션 개수 1 증가
sectionCount++;
}
else
{
// key=value 형태인 경우
string[] parts = trimmed.Split('=');
if (parts.Length == 2)
{
// values[섹션인덱스, 키인덱스]에 값 저장
values[sectionCount - 1, keyIndex] = parts[1];
keyIndex++;
}
}
}
}
// --- ini 파일 저장 기능 ---
private void SaveIniFile()
{
// StreamWriter를 이용해 파일 새로 쓰기
using (StreamWriter sw = new StreamWriter(iniFilePath))
{
for (int i = 0; i < sectionCount; i++)
{
// 섹션 제목 출력
sw.WriteLine("[" + sections[i] + "]");
// 각 섹션의 키-값 쌍 출력
for (int j = 0; j < keyCount; j++)
{
sw.WriteLine((j + 1) + "=" + values[i, j]);
}
sw.WriteLine(); // 가독성을 위한 빈 줄
}
}
}
// --- [열기 버튼 클릭 시] ini 파일 선택 및 로드 ---
private void btn_Open_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "INI 파일|*.ini"; // ini 파일만 선택 가능하게 설정
if (ofd.ShowDialog() == DialogResult.OK)
{
iniFilePath = ofd.FileName;
txt_FilePath.Text = iniFilePath; // 파일 경로 표시
// ini 내용 읽기
LoadIniFile(iniFilePath);
// 트리뷰에 표시하기
PopulateTreeView();
}
}
// --- TreeView에 섹션과 키를 표시 ---
private void PopulateTreeView()
{
tv_INI.Nodes.Clear(); // 기존 내용 지우기
for (int i = 0; i < sectionCount; i++)
{
// 섹션 노드 생성 (예: [A])
TreeNode sectionNode = new TreeNode(sections[i]);
// 섹션 밑에 키 노드(1,2,3)를 자식으로 추가
for (int j = 0; j < keyCount; j++)
{
TreeNode keyNode = new TreeNode((j + 1).ToString()); // 키 이름 예: 1, 2, 3
// Tag 속성에 섹션번호, 키번호 정보를 함께 저장
keyNode.Tag = new Tuple<int, int>(i, j);
// 섹션 노드에 키 노드 추가
sectionNode.Nodes.Add(keyNode);
}
// 최종적으로 트리뷰에 섹션 노드 추가
tv_INI.Nodes.Add(sectionNode);
}
// 전체 펼쳐서 보기
tv_INI.ExpandAll();
}
// --- 트리뷰에서 키를 클릭했을 때 ---
private void Tv_INI_AfterSelect(object sender, TreeViewEventArgs e)
{
// Level 0 = 섹션, Level 1 = 키
if (e.Node.Level == 1)
{
// Tag에 저장된 섹션/키 인덱스 가져오기
var indices = (Tuple<int, int>)e.Node.Tag;
int sectionIndex = indices.Item1;
int keyIndex = indices.Item2;
// 오른쪽 텍스트박스들에 표시
tb_Section.Text = sections[sectionIndex]; // 섹션 이름
tb_Value.Text = values[sectionIndex, keyIndex]; // 값
// 콤보박스 키 목록 업데이트
cb_Key.Items.Clear();
for (int k = 0; k < keyCount; k++)
cb_Key.Items.Add((k + 1).ToString());
// 현재 선택된 키 표시
cb_Key.SelectedIndex = keyIndex;
}
}
// --- 콤보박스에서 키를 선택했을 때 ---
private void Cb_Key_SelectedIndexChanged(object sender, EventArgs e)
{
// 현재 섹션 이름 가져오기
string sectionName = tb_Section.Text.Trim();
int sectionIdx = Array.IndexOf(sections, sectionName);
if (sectionIdx < 0) return; // 섹션이 없으면 종료
int keyIdx = cb_Key.SelectedIndex;
// 선택된 키의 값을 텍스트박스에 표시
tb_Value.Text = values[sectionIdx, keyIdx];
}
// --- [저장 버튼 클릭 시] 현재 값 저장 ---
private void btn_Save_Click(object sender, EventArgs e)
{
// 현재 선택된 섹션/키 인덱스 찾기
string sectionName = tb_Section.Text.Trim();
int sectionIdx = Array.IndexOf(sections, sectionName);
if (sectionIdx < 0) return;
int keyIdx = cb_Key.SelectedIndex;
// 변경된 값 저장
values[sectionIdx, keyIdx] = tb_Value.Text;
// ini 파일로 다시 저장
SaveIniFile();
MessageBox.Show("저장 완료!");
}
private void txt_FilePath_Click(object sender, EventArgs e)
{
}
}
}
[프로그램 개요]
목적: INI 파일을 읽고, 섹션과 키를 선택해 값을 조회 및 수정 후 저장
프레임워크: .NET Framework 4.8
UI 구성:
열기 버튼 (btn_Open) + 파일 경로 표시 텍스트박스 (txt_FilePath)
트리뷰 (tv_INI)로 전체 INI 구조 표시
섹션 입력 텍스트박스 (tb_Section)
키 선택 콤보박스 (cb_Key)
값 표시/수정 텍스트박스 (tb_Value) + 저장 버튼 (btn_Save)
[ 피드백 ]
- 지피티는 최대한 쓰지말고 참고용으로만 쓸 것 (하지만 그냥 아예 쓰지말자)
- 설명을 너무 못함. 프로그램의 흐름에 맞춰 할 것. 버튼을 눌렀을 때 어떤 함수가 실행되는지
- 클래스 다루는 법 공부하기 (클래스를 공부하면 자연스럽게 오브젝트화에 대해 알게됨)
- for 와 for each 의 차이
- using문 공부
- 반복문 1줄일 때 중괄호 생략금지 (띄어쓰기 하나만 잘못 들어가도 실행안됨. 나중에 찾기 어려움. 초보일땐 절대 금지)
- 예외처리는 꼭 try-catch문 쓸 것. (지금부터 습관 들여놔야됨. 나중에 프로그램 뻗을 때 어디서 뻗었는지 못 찾음)
- 이벤트 핸들러 동작 순서
- F10 누르면 Program.cs 부터 실행되고, 어떤 순서인지 알수있음.
- 변수는 동적할당 할 것 (정적할당하면 나중에 변수 늘어났을 때 어떡할래?)
- trim 공부하기
- 왜 배열을 썼느냐?고 물어보셔서, 처음엔 딕셔너리를 쓰려했는데 제 수준에서는 아직 사용하기 어려워서
제가 사용할 수 있는 배열을 선택했다고 하니까 이건 잘 답변했다고 하심.
- 내 방식대로. 코드 더러워도 되니까 내 방식대로 코드 짜보기. for문 1000개여도 됨.
(클래스는 나중에하고 일단 내가 생각한대로 해보기)
- 내일 퇴근 전까지 다시 완성하기
+ for와for each의 차이 / using문 / trim / try-catch 공부해서 발표하기
- 섹션 추가/삭제 기능도 넣으면 좋을듯'C#' 카테고리의 다른 글
| ini 프로그램 (노지피티) (0) | 2025.10.28 |
|---|---|
| 반복문 for VS for each 차이 (0) | 2025.10.28 |
| C# ini 파일 읽기 (0) | 2025.10.27 |
| .ini 파일 (0) | 2025.10.23 |
| 파일 입출력 (0) | 2025.10.23 |

