一个文件中读取数据并显示的程序

 

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,和判断数据的长度是否合理。
最后显示数据。


 

posted on 2008-09-05 17:01 wangwei 阅读(1129) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

文章档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜