CSV逗号分隔值文件(Comma Separated value)

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数组中。
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数据的大小和检索与一列相关的数据
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类的创建
   首先,定义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对两个构造函数进行初始化,读取物理文件并得出包含的记录数
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函数
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对象:
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文件
CSV逗号分隔值文件(Comma Separated value)_第1张图片
   单击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));
    }
}
   最后,设置好列表框的每列的宽度
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)相关函数:
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();

你可能感兴趣的:(CSV逗号分隔值文件(Comma Separated value))