CSV逗号分隔值文件(Comma Separated value)
首先,需要创建两个类:CCsvFile(派生自CStdioFile,用于从屋里文件中读取数据)和CCsvRecord(派生自CObject,适合作为CCsvFile类的Object映射成员,包含指定行的数据。
1)CCsvRecord类的创建
由于每个CSV记录都包含很多列,所以增加一个名为m_arrCloumns的CStringArray类型的成员变量(该变量包含记录的真正数据):
protected
:
CStringArray m_arrColumns;
接下来,编写构造函数,获得包含以逗号分隔记录的字符串数值。使用C语言的strtok函数来遍历字符串寻找逗号,每当找到一个逗号的时候,变量的token就包含逗号前面的值。然后,将这个值添加到m_arrColumns数组中。
CStringArray m_arrColumns;
char
DELIMITERS[]
=
"
,
"
;
CCsvRecord::CCsvRecord(LPTSTR lpszRecord)
{
char * token;
token = strtok(lpszRecord, DELIMITERS);
while (NULL != token)
{
m_arrColumns.Add(token);
token = strtok(NULL, DELIMITERS);
}
}
最后,添加返回m_arrCloumns数据的大小和检索与一列相关的数据
CCsvRecord::CCsvRecord(LPTSTR lpszRecord)
{
char * token;
token = strtok(lpszRecord, DELIMITERS);
while (NULL != token)
{
m_arrColumns.Add(token);
token = strtok(NULL, DELIMITERS);
}
}
UINT CCsvRecord::GetNbrOfColumns()
{
return m_arrColumns.GetSize();
}
CString CCsvRecord::GetColumn(UINT uiColumn)
{
CString strColumn;
if (((uiColumn >= 0 ) && (uiColumn <= (GetNbrOfColumns() - 1 ))))
{
strColumn = m_arrColumns[uiColumn];
}
return strColumn;
}
2)CCsvFile类的创建
{
return m_arrColumns.GetSize();
}
CString CCsvRecord::GetColumn(UINT uiColumn)
{
CString strColumn;
if (((uiColumn >= 0 ) && (uiColumn <= (GetNbrOfColumns() - 1 ))))
{
strColumn = m_arrColumns[uiColumn];
}
return strColumn;
}
首先,定义CCsvFile对象的集合,使用模板化的集合来保证类型的安全,并定义数组m_CsvRecordArray。EnsOfFile值是一个枚举型的值,用来判断是否到达文件尾。FileExists判断文件是否存在。m_dwNumberOfRecords返回数组的大小,即表示文件中包含的记录数。
typedef CTypedPtrArray
<
CObArray, CCsvRecord
*>
CCsvRecordArray;
class CCsvFile : public CStdioFile
{
public :
CCsvFile(LPSTR lpszFileName);
CCsvFile(CString & strFileName);
~ CCsvFile();
protected :
void Initialize(LPSTR lpszFileName);
public :
enum
{
EndOfFile = - 1
};
public :
static BOOL FileExists(LPCTSTR lpszFileName)
{
return ( 0 == (_access(lpszFileName, 4 )));
}
protected :
DWORD LoadRecords();
protected :
DWORD m_dwNumberOfRecords;
public :
DWORD GetNumberOfRecords()
{
return m_dwNumberOfRecords;
}
protected :
CCsvRecordArray m_CsvRecordArray;
public :
UINT GetStartPosition();
void GetNextAssoc(UINT & rPosition, CCsvRecord ** ppCsvRecord);
};
利用Initialize对两个构造函数进行初始化,读取物理文件并得出包含的记录数
class CCsvFile : public CStdioFile
{
public :
CCsvFile(LPSTR lpszFileName);
CCsvFile(CString & strFileName);
~ CCsvFile();
protected :
void Initialize(LPSTR lpszFileName);
public :
enum
{
EndOfFile = - 1
};
public :
static BOOL FileExists(LPCTSTR lpszFileName)
{
return ( 0 == (_access(lpszFileName, 4 )));
}
protected :
DWORD LoadRecords();
protected :
DWORD m_dwNumberOfRecords;
public :
DWORD GetNumberOfRecords()
{
return m_dwNumberOfRecords;
}
protected :
CCsvRecordArray m_CsvRecordArray;
public :
UINT GetStartPosition();
void GetNextAssoc(UINT & rPosition, CCsvRecord ** ppCsvRecord);
};
CCsvFile::CCsvFile(LPSTR lpszFileName)
{
Initialize(lpszFileName);
}
CCsvFile::CCsvFile(CString & strFileName)
{
Initialize(strFileName.GetBuffer( 0 ));
}
void CCsvFile::Initialize(LPSTR lpszFileName)
{
m_dwNumberOfRecords = 0 ;
ASSERT(lpszFileName != NULL);
ASSERT(AfxIsValidString(lpszFileName));
if (CCsvFile::FileExists(lpszFileName))
{
if (Open(lpszFileName, CFile::modeRead))
{
m_dwNumberOfRecords = LoadRecords();
}
}
}
DWORD CCsvFile::LoadRecords()
{
m_dwNumberOfRecords = 0 ;
CCsvRecord * pCsvRecord;
CString strRecord;
while (ReadString(strRecord))
{
pCsvRecord = new CCsvRecord(strRecord.GetBuffer( 0 ));
ASSERT(pCsvRecord);
if (pCsvRecord)
{
m_CsvRecordArray.Add(pCsvRecord);
}
strRecord.ReleaseBuffer();
}
return m_CsvRecordArray.GetSize();
}
增加两个遍历记录数组的函数,GetStrarPosition和GetNextAssoc函数
{
Initialize(lpszFileName);
}
CCsvFile::CCsvFile(CString & strFileName)
{
Initialize(strFileName.GetBuffer( 0 ));
}
void CCsvFile::Initialize(LPSTR lpszFileName)
{
m_dwNumberOfRecords = 0 ;
ASSERT(lpszFileName != NULL);
ASSERT(AfxIsValidString(lpszFileName));
if (CCsvFile::FileExists(lpszFileName))
{
if (Open(lpszFileName, CFile::modeRead))
{
m_dwNumberOfRecords = LoadRecords();
}
}
}
DWORD CCsvFile::LoadRecords()
{
m_dwNumberOfRecords = 0 ;
CCsvRecord * pCsvRecord;
CString strRecord;
while (ReadString(strRecord))
{
pCsvRecord = new CCsvRecord(strRecord.GetBuffer( 0 ));
ASSERT(pCsvRecord);
if (pCsvRecord)
{
m_CsvRecordArray.Add(pCsvRecord);
}
strRecord.ReleaseBuffer();
}
return m_CsvRecordArray.GetSize();
}
UINT CCsvFile::GetStartPosition()
{
UINT uiPosition;
if ( 0 < m_CsvRecordArray.GetSize())
{
uiPosition = 0 ;
}
else
{
uiPosition = CCsvFile::EndOfFile;
}
return uiPosition;
}
void CCsvFile::GetNextAssoc(UINT & uiPosition, CCsvRecord ** ppCsvRecord)
{
UINT uiNewPosition = CCsvFile::EndOfFile;
* ppCsvRecord = NULL;
UINT nRecords = m_CsvRecordArray.GetSize();
if (uiPosition >= 0 && uiPosition <= (nRecords - 1 ))
{
* ppCsvRecord = m_CsvRecordArray[uiPosition];
if ( (uiPosition + 1 ) <= (nRecords - 1 ) )
{
uiNewPosition = uiPosition + 1 ;
}
}
uiPosition = uiNewPosition;
}
最后,编写西沟函数来清楚前面分配的CCsvRecord对象:
{
UINT uiPosition;
if ( 0 < m_CsvRecordArray.GetSize())
{
uiPosition = 0 ;
}
else
{
uiPosition = CCsvFile::EndOfFile;
}
return uiPosition;
}
void CCsvFile::GetNextAssoc(UINT & uiPosition, CCsvRecord ** ppCsvRecord)
{
UINT uiNewPosition = CCsvFile::EndOfFile;
* ppCsvRecord = NULL;
UINT nRecords = m_CsvRecordArray.GetSize();
if (uiPosition >= 0 && uiPosition <= (nRecords - 1 ))
{
* ppCsvRecord = m_CsvRecordArray[uiPosition];
if ( (uiPosition + 1 ) <= (nRecords - 1 ) )
{
uiNewPosition = uiPosition + 1 ;
}
}
uiPosition = uiNewPosition;
}
CCsvFile::
~
CCsvFile()
{
CCsvRecord * pCsvRecord;
for ( int i = m_CsvRecordArray.GetUpperBound(); i > - 1 ; i -- )
{
pCsvRecord = m_CsvRecordArray[i];
m_CsvRecordArray.RemoveAt(i);
ASSERT(pCsvRecord);
if (pCsvRecord)
{
delete pCsvRecord;
}
}
VERIFY( 0 == m_CsvRecordArray.GetSize());
}
3)打印和显示CSV文件
{
CCsvRecord * pCsvRecord;
for ( int i = m_CsvRecordArray.GetUpperBound(); i > - 1 ; i -- )
{
pCsvRecord = m_CsvRecordArray[i];
m_CsvRecordArray.RemoveAt(i);
ASSERT(pCsvRecord);
if (pCsvRecord)
{
delete pCsvRecord;
}
}
VERIFY( 0 == m_CsvRecordArray.GetSize());
}
单击Open事件,在实例化CCsvFile之后,只需在for循环中使用GetStratPosition和GetNextAssoc函数来检索CCsvRecord对象。并对每条记录调用InsertDataIntoListView函数。
void
CCViewCSVDlg::OnButton1()
{
CFileDialog dlg( true );
if (IDOK == dlg.DoModal())
{
try
{
m_strFileName = dlg.GetPathName();
UpdateData(FALSE);
CCsvFile file(dlg.GetPathName());
CCsvRecord * pCsvRecord;
for (UINT uiRow = file.GetStartPosition();
CCsvFile::EndOfFile != uiRow;)
{
// get the actual record
file.GetNextAssoc(uiRow, & pCsvRecord);
if (pCsvRecord)
{
InsertDataIntoListView(uiRow, * pCsvRecord);
}
}
}
catch (CFileException * pe)
{
pe -> ReportError();
}
}
SizeAllColumns();
}
void CCViewCSVDlg::InsertDataIntoListView(UINT uiRow, CCsvRecord & csvRecord)
{
// For each column in the passed record
for ( int iCol = 0 ; iCol < csvRecord.GetNbrOfColumns(); iCol ++ )
{
// If this is the first row in the listview
if (uiRow == 1 )
{
// Create the listview columns.
CString strColumnName;
strColumnName.Format( " Col %ld " , iCol);
m_lstFileContents.InsertColumn(iCol, strColumnName);
}
if (iCol == 0 )
m_lstFileContents.InsertItem(m_lstFileContents.GetItemCount(),
csvRecord.GetColumn(iCol));
else
m_lstFileContents.SetItemText(m_lstFileContents.GetItemCount() - 1 ,
iCol,csvRecord.GetColumn(iCol));
}
}
最后,设置好列表框的每列的宽度
{
CFileDialog dlg( true );
if (IDOK == dlg.DoModal())
{
try
{
m_strFileName = dlg.GetPathName();
UpdateData(FALSE);
CCsvFile file(dlg.GetPathName());
CCsvRecord * pCsvRecord;
for (UINT uiRow = file.GetStartPosition();
CCsvFile::EndOfFile != uiRow;)
{
// get the actual record
file.GetNextAssoc(uiRow, & pCsvRecord);
if (pCsvRecord)
{
InsertDataIntoListView(uiRow, * pCsvRecord);
}
}
}
catch (CFileException * pe)
{
pe -> ReportError();
}
}
SizeAllColumns();
}
void CCViewCSVDlg::InsertDataIntoListView(UINT uiRow, CCsvRecord & csvRecord)
{
// For each column in the passed record
for ( int iCol = 0 ; iCol < csvRecord.GetNbrOfColumns(); iCol ++ )
{
// If this is the first row in the listview
if (uiRow == 1 )
{
// Create the listview columns.
CString strColumnName;
strColumnName.Format( " Col %ld " , iCol);
m_lstFileContents.InsertColumn(iCol, strColumnName);
}
if (iCol == 0 )
m_lstFileContents.InsertItem(m_lstFileContents.GetItemCount(),
csvRecord.GetColumn(iCol));
else
m_lstFileContents.SetItemText(m_lstFileContents.GetItemCount() - 1 ,
iCol,csvRecord.GetColumn(iCol));
}
}
void
CCViewCSVDlg::SizeAllColumns()
{
CHeaderCtrl * pHeader = m_lstFileContents.GetHeaderCtrl();
ASSERT(pHeader);
if (pHeader)
{
// Turn off redraw until the columns have all
// been resized
m_lstFileContents.SetRedraw(FALSE);
for ( int iCurrCol = 0 ;
iCurrCol < pHeader -> GetItemCount();
iCurrCol ++ )
{
m_lstFileContents.SetColumnWidth(iCurrCol, LVSCW_AUTOSIZE);
int nCurrWidth = m_lstFileContents.GetColumnWidth(iCurrCol);
m_lstFileContents.SetColumnWidth(iCurrCol,
LVSCW_AUTOSIZE_USEHEADER);
int nColHdrWidth = m_lstFileContents.GetColumnWidth(iCurrCol);
m_lstFileContents.SetColumnWidth(iCurrCol,
max(nCurrWidth, nColHdrWidth));
}
// Now that sizing is finished, turn redraw back on and
// invalidate so that the control is repainted
m_lstFileContents.SetRedraw(TRUE);
m_lstFileContents.Invalidate();
}
}
4)相关函数:
{
CHeaderCtrl * pHeader = m_lstFileContents.GetHeaderCtrl();
ASSERT(pHeader);
if (pHeader)
{
// Turn off redraw until the columns have all
// been resized
m_lstFileContents.SetRedraw(FALSE);
for ( int iCurrCol = 0 ;
iCurrCol < pHeader -> GetItemCount();
iCurrCol ++ )
{
m_lstFileContents.SetColumnWidth(iCurrCol, LVSCW_AUTOSIZE);
int nCurrWidth = m_lstFileContents.GetColumnWidth(iCurrCol);
m_lstFileContents.SetColumnWidth(iCurrCol,
LVSCW_AUTOSIZE_USEHEADER);
int nColHdrWidth = m_lstFileContents.GetColumnWidth(iCurrCol);
m_lstFileContents.SetColumnWidth(iCurrCol,
max(nCurrWidth, nColHdrWidth));
}
// Now that sizing is finished, turn redraw back on and
// invalidate so that the control is repainted
m_lstFileContents.SetRedraw(TRUE);
m_lstFileContents.Invalidate();
}
}
token = strtok(lpszRecord, DELIMITERS);
typedef CTypedPtrArray<CObArray, CCsvRecord*> CCsvRecordArray;
return (0 == (_access(lpszFileName, 4)));
ASSERT(AfxIsValidString(lpszFileName));
for (int i = m_CsvRecordArray.GetUpperBound(); i > -1; i--)
m_CsvRecordArray.RemoveAt(i);
VERIFY(0 == m_CsvRecordArray.GetSize());
pCsvRecord = new CCsvRecord(strRecord.GetBuffer(0));
strRecord.ReleaseBuffer();
m_lstFileContents.InsertColumn(iCol, strColumnName);
m_lstFileContents.InsertItem(m_lstFileContents.GetItemCount(),csvRecord.GetColumn(iCol));
m_lstFileContents.SetItemText(m_lstFileContents.GetItemCount()-1,iCol,csvRecord.GetColumn(iCol));
m_lstFileContents.SetRedraw(FALSE);
m_lstFileContents.SetColumnWidth(iCurrCol, LVSCW_AUTOSIZE);
int nCurrWidth = m_lstFileContents.GetColumnWidth(iCurrCol);
m_lstFileContents.SetRedraw(TRUE);
m_lstFileContents.Invalidate();