三種讀寫方式
1.CFile
CFile file;
CFileException eErr;
CString strFileName = "f://txt1.wkb";
LPCTSTR lpszFileName = strFileName;
try
{
if(!file.Open(lpszFileName, CFile::modeReadWrite | CFile::modeCreate, &eErr))
{
return ;
}
CString strbuf = "hello";
file.Write(strbuf,strbuf.GetLength());
strbuf = "";
file.SeekToBegin();
int iFileLen = file.GetLength();
file.Read( strbuf.GetBuffer(iFileLen),iFileLen);
strbuf.ReleaseBuffer();
file.Close();
}
catch (CFileException* e)
{
AfxMessageBox("Operating the file failed.");
}
2.API
char * pchTxtFileName="f://txt.txt";
HANDLE hFile=::CreateFile(pchTxtFileName,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
CString strTmp = "hello";
DWORD dNumOfAccess;
::WriteFile(hFile,strTmp,strTmp.GetLength(),&dNumOfAccess,NULL);
int nLength=::SetFilePointer(hFile,0,NULL,FILE_END);
char *pData=new char [nLength+1];
memset(pData,0,nLength+1);
::SetFilePointer(hFile,0,NULL,FILE_BEGIN);
::ReadFile(hFile,pData,nLength,&dNumOfAccess,NULL);
delete[] pData;
CloseHandle(hFile);
3.FILE
char *pDt = new char [100];
memset(pDt,'a',3);
pDt[3] = '/0';
FILE * pFile=fopen(pchTxtFileName,"wt+");
fprintf(pFile,"%s/r/n",pDt);
memset(pDt,0,3);
fseek(pFile,0,SEEK_SET);
fscanf(pFile,"%s/r/n",pDt);
delete [] pDt;
fclose(pFile);
二進制檔案和文本檔案
介紹
大家都知道計算機的存儲在實體上是二進制的,是以文本檔案與二進制檔案的差別并不是實體上的,而是邏輯上的。這兩者隻是在編碼層次上有差異。
簡單來說,文本檔案是基于字元編碼的檔案,常見的編碼有ASCII編碼,UNICODE編碼等等。二進制檔案是基于值編碼的檔案,你可以根據具體應用,指定某個值是什麼意思(這樣一個過程,可以看作是自定義編碼)。
從上面可以看出文本檔案基本上是定長編碼的,基于字元嘛,每個字元在具體編碼中是固定的,ASCII碼是8個比特的編碼,UNICODE一般占16個比特。而二進制檔案可看成是變長編碼的,因為是值編碼嘛,多少個比特代表一個值,完全由你決定。大家可能對BMP檔案比較熟悉,就拿它舉例子吧,其頭部是較為固定長度的檔案頭資訊,前2位元組用來記錄檔案為BMP格式,接下來的8個位元組用來記錄檔案長度,再接下來的4位元組用來記錄bmp檔案頭的長度。。。大家可以看出來了吧,其編碼是基于值的(不定長的,2、4、8位元組長的值都有),是以BMP是二進制檔案。
二進制檔案把記憶體中的資料按其在記憶體中存放形式原樣輸出到磁盤上。
文本檔案:把檔案看作是一個一個的字元序列。
讀寫
可用FILE * pFile=fopen(pchTxtFileName,"wt+");中的第二個參數決定讀寫二進制檔案還是文本檔案。具體可以檢視MSDN。
CFile一般是讀寫檔案檔案。
寫Ansi文本檔案和Unicode文本檔案
Anis文本檔案
一般常見的是Ansi文本檔案,例如上面的三種讀寫方式的寫檔案方式。
Unicode文本檔案
//寫Unicode文本檔案,頭個位元組xfeff,低位xff寫在前
CFile file;
file.Open(_T("1.txt"), CFile::modeWrite | CFile::modeCreate);
//檔案開頭
file.SeekToBegin();
// 決定是Ansi檔案還是Unicode檔案
file.Write("/xff/xfe", 2); // 沒有這一句,則為Ansi檔案,這裡則表示Unicode檔案
//寫入内容
file.Write("abc", 3);
file.Flush();
file.Close();
按行讀取文本,CStdioFile擴充類:CStdioFileEx
支援寬位元組、多位元組環境;支援Ansi、Unicode文本;支援中英文。
最初,直接從網上下了CStdioFileEx類使用,發現好像并不好用。于是自己決定重寫。于是花了一天時間,在各種環境下檢視微軟是如何讀文本的。剛開始一直被Unicode文本的讀取方式迷惑,知道最後才發現,要用二進制方式讀取,否則自動把每一個位元組擴充成2個位元組。這就是造成亂碼的根本原因。查找到原因,就好寫了。當然是把CStdioFile的代碼copy過來,根據正确環境,用正确的函數。結果發現,網上也是這種方式。雖然解決方法都是一樣,但習慣或者思維方式不一樣,是以才覺得他的類并不好用。總是覺得,他考慮的有點過于複雜,把簡單問題複雜化了。是以按照自己的思路,完完整整的,一字一句的寫下了自己的類。
有時,快樂本身,就是一種過程,自己的過程。也許盡管是别人走過的過程,但卻屬于自己的過程,不一樣的過程。
好了,廢話不多說。源碼如下:
ini配置檔案讀寫
在Windows中我們可以使用系統資料庫或者 ini 檔案(Profile)來儲存少量資料,如程式的初始化資訊,使用者設定的資料等。
通過應用程式,寫系統資料庫
AfxGetApp()->WriteProfileString(sPath,sKeyPath,m_sPath);
AfxGetApp()->GetProfileString(sFilePath,sKeyFilePath,"");
ini檔案
ini檔案(即Initialization file),由若幹個節(Section)組成,每個Section由若幹鍵(Key)組成,每個Key可以賦相應的值。讀寫ini檔案實際上就是讀寫某個的Section中相應的Key的值。
讀寫ini檔案函數
GetPrivateProfileString 讀取INI檔案指定塊中的鍵名對應的字元串。
GetPrivateProfileInt 讀取INI檔案指定塊中的鍵名對應的整數值。
GetPrivateProfileStruct 讀取INI檔案指定塊中的鍵名對應的資料
GetPrivateProfileSection 讀取INI檔案指定塊中的所有鍵名及其對應值。
GetPrivateProfileSectionNames 讀取一INI檔案中所有的塊名。
GetProfileInt 讀取win.ini中指定塊中的鍵名對應的整數值。
GetProfileString 讀取win.ini中指定塊中的鍵名的對應值。
GetProfileSection 讀取win.ini中指定塊中所有的鍵名及其值。
(win.ini,是Windows系統的一個基本系統配置檔案。在C:/Windows下,故用GetProfileInt等函數時,不需要指定路徑。但不推薦儲存私有消息。)
WritePrivateProfileSection 替換INI檔案中指定塊中所有鍵名對應的值。
WritePrivateProfileString 把給定的鍵名及其值寫入到指定INI檔案的相應塊中。
WritePrivateProfileStruct 把指定的鍵名及其資料寫入到指定INI檔案的塊中。
WriteProfileSection 替換win.ini中指定塊的所有鍵名對應的值。
WriteProfileString 将給定的鍵名及值寫入win.ini中對應的塊中。
例子
// --------------------------------------------------------------------------------------------
// [Section1]
// Key1=1
// Key2=2
// Key3=3
//
// [Section2]
// Key4=4
// Key5=5
// Key6=6
// --------------------------------------------------------------------------------------------
#define MAX_COUNT 1000
CString iniFile(_T(".//1.ini"));
// 讀取指定塊中的鍵名對應的字元串。
CString val;
GetPrivateProfileString(_T("Section1"), _T("Key1"), _T(""), val.GetBuffer(MAX_COUNT), MAX_COUNT, iniFile);
val.ReleaseBuffer(); // val = "1"
// 讀取指定塊中的鍵名對應的整數。
int nVal = GetPrivateProfileInt(_T("Section1"), _T("Key1"), 0, iniFile); // nVal = 1
// 把Key2=2 改成Key2=222
WritePrivateProfileString(_T("Section1"), _T("Key2"), _T("222"), iniFile);
删除鍵值或節
回顧一下WriteProfileString函數的說明
BOOL WriteProfileString(
LPCTSTR lpAppName, // 節的名字,是一個以0結束的字元串
LPCTSTR lpKeyName, // 鍵的名字,是一個以0結束的字元串。若為NULL,則删除整個節
LPCTSTR lpString // 鍵的值,是一個以0結束的字元串。若為NULL,則删除對應的鍵
)
由此可見,要删除某個節,隻需要将WriteProfileString第二個參數設為NULL即可。而要删除某個鍵,則隻需要将該函數的第三個參數設為 NULL即可。這是删除系統的win.ini中的節或鍵,類似的,要删除自己定義的ini檔案中的節或鍵,也可做相同的操作。
如:
::WriteProfileString("Test",NULL,NULL); //删除win.ini中的Test節
::WriteProfileString("Test","id",NULL); //删除win.ini中的id鍵
::WritePrivateProfileString("Test",NULL,NULL,".//ex1.ini"); //删除ex1.ini中的Test節
::WritePrivateProfileString("Test","id",NULL,".//ex1.ini"); //删除ex1.ini中的id鍵
讀取ini檔案所有的節名
要判斷一個ini檔案中有多少個節,最簡單的辦法就是将所有的節名都找出來,然後統計節名的個數。而要将所有的節名找出來,使用GetPrivateProfileSectionNames函數就可以了,其原型如下:
DWORD GetPrivateProfileSectionNames(
LPTSTR lpszReturnBuffer, // 指向一個緩沖區,用來儲存傳回的所有節名
DWORD nSize, // 參數lpszReturnBuffer的大小
LPCTSTR lpFileName // 檔案名,若該ini檔案與程式在同一個目錄下,
//也可使用相對路徑,否則需要給出絕度路徑
)
/* ------------------------------------------------------------------------------------------------
Function Name : GetSectionNames
Describe : 讀取ini檔案中所有的節名
Parameters :
CStringArray& sections ----- [out] 所有節名字元串數組
LPCTSTR lpIniFile ----- [in] ini檔案路徑
Return type : int ----- 節名個數
------------------------------------------------------------------------------------------------
I D :
Others :
------------------------------------------------------------------------------------------------
Author : Alsmile Date : 2010-8-12
Project :
Version : 1.0.0.1
Module :
------------------------------------------------------------------------------------------------
History :
/* --------------------------------------------------------------------------------------------- */
int GetSectionNames(CStringArray& sections, LPCTSTR lpIniFile)
{
const int MaxStringCount = 3000;
int count(0);
try
{
// 所有節名字元串數組
TCHAR szSectionNames[MaxStringCount] = {0};
int length = GetPrivateProfileSectionNames(szSectionNames, MaxStringCount, lpIniFile);
int index(0);
for(int i = 0; i < length; ++i)
{
if(szSectionNames[i] == '/0')
{
sections.Add(&szSectionNames[index]);
TRACE(sections[count]);
++count;
index = i + 1;
//當兩個相鄰的字元都是時,則所有的節名都已找到,循環終止
if(szSectionNames[index] == 0)
{
break;
}
}
}
}
catch (...)
{
}
return count;
}
讀取ini檔案中指定節下面的所有鍵名和鍵值
/* ------------------------------------------------------------------------------------------------
Function Name : GetSectionKeysValues
Describe : 讀取ini檔案中指定節下的所有鍵名和鍵值
Parameters :
CStringArray& keys ----- [out] 所有鍵名字元串數組
CStringArray& vals ----- [out] 所有鍵值字元串數組
LPCTSTR lpSection ----- [in] 指定節名
LPCTSTR lpIniFile ----- [in] ini檔案路徑
Return type : int ----- 鍵個數
------------------------------------------------------------------------------------------------
I D :
Others :
------------------------------------------------------------------------------------------------
Author : Alsmile Date : 2010-8-12
Project :
Version : 1.0.0.1
Module :
------------------------------------------------------------------------------------------------
History :
/* --------------------------------------------------------------------------------------------- */
int GetSectionKeysValues(CStringArray& keys, CStringArray& vals, LPCTSTR lpSection, LPCTSTR lpIniFile)
{
const int MaxStringCount = 6000;
int count(0);
TRACE(_T("/n"));
try
{
// 包括key和value的總字元串
TCHAR szKeysVals[MaxStringCount] = {0};
int length = GetPrivateProfileSection(lpSection, szKeysVals, MaxStringCount, lpIniFile);
int index(0);
for(int i = 0; i < length; ++i)
{
if (szKeysVals[i] == '/0')
{
if (i != index)
{
CString lineText(&szKeysVals[index]);
keys.Add(lineText.Left(lineText.Find('=')));
TRACE(keys[count] + _T("="));
vals.Add(lineText.Mid(lineText.Find('=') + 1));
TRACE(vals[count] + _T("/n"));
++count;
}
index = i + 1;
}
}
}
catch (...)
{
}
return count;
}
xml檔案讀寫
推薦使用 tinyXML(使用簡單)或 CMarkup
tinyXML:tinyxml使用筆記與總結 (請自己網上google)
CMarkup:CMarkup7.2 概述 CMarkUp函數簡介 (請自己網上google這兩個文章)
源文檔 <http://blog.csdn.net/alsmile/article/details/6530078>