Cấu trúc cơ bản của một tệp INI được tổ chức thành các phần (section), khóa (key) và giá trị (value). Định dạng chuẩn thường thấy như sau:
[Ten_Phan]
Khoa = Gia_Tri
Khoa_2 = Gia_Tri_2
Một tệp INI có thể chứa nhiều phần khác nhau. Để tương tác với tệp cấu hình này trong môi trường Windows, chúng ta sử dụng các hàm API có sẵn.
Các hàm Windows API xử lý tệp INI
Cần bao gồm thư viện <Windows.h> để sử dụng các hàm dưới đây:
- WritePrivateProfileString: Dùng để ghi một chuỗi ký tự vào tệp.
- GetPrivateProfileString: Đọc giá trị chuỗi từ một khóa cụ thể, có hỗ trợ giá trị mặc định.
- GetPrivateProfileInt: Đọc và chuyển đổi giá trị của khóa thành kiểu số nguyên.
- GetPrivateProfileSectionNames: Truy xuất danh sách tên của tất cả các phần (section) có trong tệp.
- GetPrivateProfileSection: Lấy toàn bộ cặp khóa-giá trị thuộc một phần được chỉ định.
Minh họa sử dụng API
Dưới đây là đoạn mã thể hiện cách gọi các hàm cơ bản để đọc và ghi dữ liệu:
#include <Windows.h>
void ExecuteIniOperations()
{
const wchar_t* configPath = L"D:\\app_settings.ini";
// Ghi dữ liệu vào tệp
WritePrivateProfileStringW(L"Network", L"ServerIP", L"192.168.1.10", configPath);
// Đọc dữ liệu dạng chuỗi
wchar_t textBuffer[128];
GetPrivateProfileStringW(L"Network", L"ServerIP", L"0.0.0.0", textBuffer, 128, configPath);
// Đọc dữ liệu dạng số nguyên
int timeout = GetPrivateProfileIntW(L"Network", L"Timeout", 30, configPath);
// Lấy danh sách tên các section
GetPrivateProfileSectionNamesW(textBuffer, 128, configPath);
// Lấy toàn bộ key-value trong section Network
GetPrivateProfileSectionW(L"Network", textBuffer, 128, configPath);
}
Đóng gói thành lớp C++
Để tái sử dụng và quản lý mã nguồn tốt hơn, chúng ta có thể thiết kế một lớp wrapper bao bọc các API này:
#pragma once
#include <Windows.h>
#include <string>
class IniConfiguration
{
public:
explicit IniConfiguration(const std::wstring& filePath)
: m_filePath(filePath)
{}
bool SaveString(const std::wstring& section, const std::wstring& key, const std::wstring& value)
{
return WritePrivateProfileStringW(section.c_str(), key.c_str(), value.c_str(), m_filePath.c_str());
}
int LoadInteger(const std::wstring& section, const std::wstring& key, int fallbackValue = 0)
{
return GetPrivateProfileIntW(section.c_str(), key.c_str(), fallbackValue, m_filePath.c_str());
}
DWORD FetchSectionNames(wchar_t* buffer, DWORD bufferSize)
{
return GetPrivateProfileSectionNamesW(buffer, bufferSize, m_filePath.c_str());
}
DWORD FetchSectionData(const std::wstring& section, wchar_t* buffer, DWORD bufferSize)
{
return GetPrivateProfileSectionW(section.c_str(), buffer, bufferSize, m_filePath.c_str());
}
private:
std::wstring m_filePath;
};