void CMyDlg::OnBrowse()


{
// TODO: Add your control notification handler code here

// Choose a folder
TCHAR szFull[_MAX_PATH];
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
::GetModuleFileName(NULL, szFull, sizeof(szFull)/sizeof(TCHAR));
_tsplitpath(szFull, szDrive, szDir, NULL, NULL);
_tcscpy(szFull, szDrive);
_tcscat(szFull, szDir);
m_strPath = CString(szFull);
// MessageBox(m_strPath);
// select a file path
CListBox *pCtrl = (CListBox *)GetDlgItem( IDC_LIST1 ) ;
CFileFind finder;
// strWildcard += _T("C:\\*.*");
BOOL bWorking = finder.FindFile( m_strPath+_T("*.data")) ;
CString filename;
while(bWorking)

{
bWorking = finder.FindNextFile();
if(finder.IsDots()) //ignore . and ..
continue;
if(finder.IsDirectory())

{
//deal with folder, may recursively search files
}
else

{
filename = finder.GetFileName();
pCtrl->AddString(filename);
UpdateData(FALSE);
}
}
finder.Close();
// MessageBox(m_strPath);
}
第一步是先獲得一個要打開的文件的列表,并在ListBox中顯示出來,也就是對單擊瀏覽按鈕的消息響應。
代碼解釋:
_MAX_DRIVE:Maximum length of drive component,
_MAX_PATH:Maximum length of full path,
_MAX_DIR:Maximum length of directory component。
GetModuleFileName是SDK函數其原型為:
DWORD GetModuleFileName(
HMODULE hModule, // handle to module
LPTSTR lpFilename, // path buffer
DWORD nSize // size of buffer
);
若函數成功,返回的是TCHAR型字符的長度。如果函數失敗則返回0。
第一個參數是要查找的組件或者模塊的句柄。如果是NULL則返回當前程序的路徑。
第二個參數是一個指針,指向一塊buffer于接受路徑字符串,就用剛剛定義的TCHAR型數組szFull的名字。
第三個參數是buffer的長度,要求是保存TCHAR型字符的長度。
TCHAR型16位Unicode字符集中的字符類型,對應8位ANSI字符集中char型。Unicode字符集在Windows2000和WindowsNT上有更高的效率。
通過GetModuleFileName函數就將當前程序的路徑傳遞給了szFull數組,但是現在的路徑是當前應用程序的,而我們要獲得的是當前的目錄路徑。
_tsplitpath函數就是用于分割路徑的,函數原型如下:
void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext );
函數的參數意義一目了然,最后一個參數得到的文件擴展名是帶"."的。
使用這個函數要包含<stdlib.h>頭文件。
m_strPath是一個Cdlg類的成員變量,用于保存這個路徑,在以后打開文件時還要用到。
CFileFind類是從CObject類中繼承下來的,在繼承圖表中并不在File service中,而是在Internet service中,在這里只用它尋找本地文件。
在這段代碼中要在尋找的文件是以“.data”為擴展名的,所以搜索名字為m_strPath+"*.data"的文件。FindFile的返回值是一個布爾變量,非零值表示成功。FindNextFile返回非零值表示有更多的文件,零值表示是最后一個文件。在做有關文件的屬性的操作之前總使用該調用該函數至少一次。這兩個函數的原型如下:
virtual BOOL FindFile( LPCTSTR pstrName = NULL, DWORD dwUnused = 0 );
virtual BOOL FindNextFile( );
下邊的條件語句是忽略找到的文件夾和"."以及".."的。也可以在文件夾中做遞歸搜索,可以得到包括當前目錄子目錄的文件。
這樣就將當前目錄下的所有data文件(不包括子文件夾)添加到ListBox列表中了。如圖:

第二步就是雙擊選中一文件,能將文件的數據用波形的方式顯示,在這里用的是NI的Messurement Stdio控件的評估版,如果將數組讀出來也可以自己制圖。先添加ListBox的雙擊消息響應,void CMyDlg::OnDblclkList1。注意在空間中的notify風格應該是選中狀態。
消息響應函數如下:
void CMyDlg::OnDblclkList1()


{
// TODO: Add your control notification handler code here
// MessageBox(m_strPath);
CString fileName;
CListBox *pCtrl = (CListBox *)GetDlgItem(IDC_LIST1);
pCtrl->GetText(pCtrl->GetCurSel(),fileName);
m_strPath += fileName;
// MessageBox(m_strPath);
CStdioFile file(m_strPath, CStdioFile::modeRead);
CString strData;
//double *data1;
//double *data2;
int sampleRate = 0;
int sampleTime = 0;
// int dataLen = 0;
int lineNo = 0;

file.ReadString(strData);
sampleRate = atoi(strData);
file.ReadString(strData);
sampleTime = atoi(strData);
dataLen = sampleRate*sampleTime;
data1 = new double[dataLen];
data2 = new double[dataLen];


while(file.ReadString(strData))

{
if(strData == "start")
continue;
if(strData == "end")
break;
else

{
if((lineNo/dataLen) < 1)

{
data1[lineNo] = atof(strData);
++lineNo;
}
else if((lineNo/dataLen) < 2)

{
data2[lineNo-(int)(lineNo/dataLen)*dataLen] = atof(strData);
lineNo++;
}
}
}
if(lineNo!=dataLen*2)
MessageBox("數據損壞");
else

{
double newTime = 0;
double sinePoint;
for ( int i = 1 ; i <dataLen ; i ++)

{
newTime++;
sinePoint = data2[i];
m_graph.ChartXY(newTime, sinePoint);
}

}
}
代碼解釋:
首先說明一下data文件的格式,就是普通的文本文件改掉后綴名,以免誤打開損壞數據。數據保存的格式為單列。第一個數字表示采樣率,第二個數字表示采樣時間,start是開始的標識,end是數據結束的標識。采樣率*采樣時間是一個通道的數據長度,這里有兩個通道。
下面解釋代碼:
第一步定義的filename與OnBrows消息響應中的并無關聯(參見名字作用域說明),它保存了雙擊的文件名字符。
CListBox的成員函數GetCurSel原型如下:
int GetCurSel( ) const;
返回的int型變量是雙擊選中的文件在列表的索引號,是以0為開始自上向下的序號。
CListBox::GetText原型如下:
void GetText( int nIndex, CString& rString ) const;
兩個參數分別為索引號和要接受索引號對應的文件的名字的CString類型對象。再同CDlg的成員變量保存的路徑相加就獲得了雙擊選中的文件的全路徑。
CStdioFile是繼承CFile的類,它提供了一次讀入文件的一行到CString對象的方法:ReadString。并且將當前的位置移動到下一行,所以可以連續使用它來讀取數據。ReadString原型如下:
BOOL ReadString(CString& rString);
sampleRate和sampleTime分別是采樣率和采樣時間。
先將采樣率和采樣時間讀出來計算出一路通道的數據長度,然后分配內存給保存數據的數組。判斷開始標記start,開始讀取數據。并且通過lineNo變量判斷數據屬于通道1還是通道2,和判斷數據的長度是否合理。
最后顯示數據。
