当我发现解决如题所示的问题之后,我发现我真是吃饱了没事做。实际上,写代码的我还没吃饭,留给我的事情还是很多。其实,很简单,但是我搞得有点小复杂,再次证明我做好事不容易,捣乱很在行。但是,不管怎样,还是所说过程吧。
问题是在文件打开对话框中选择多个文件,我所遇到的实际问题中这些文件是批处理生成的因此文件名很有规律均为StrLigX.jpg(因为要做一些结构光方面的实验,所以文件名命名为StructureLightX.jpg,X为整数,后来改成缩写名,原因见后)。如果用过CfileDialog类的选择多个文件的朋友就知道,如果文件名有一定规律(如整数),该类的函数会自动对先后选择的文件进行一些排序。那首先看看如何实现打开多个文件,其实很简单,只要将m_ofn的Flags设为OFN_ALLOWMULTISELECT即可,当然也可以在实例化是设置,我比较喜欢后者,然后利用GetStartPosition函数和GetNextPathName函数的组合读取多个文件
CFileDialog dlg(TRUE,"","*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT);
vector<CString> vStrPathName;
if(dlg.DoModal()==IDOK)
{
POSITION mPos = dlg.GetStartPosition();
while(mPos!=NULL)
{
vStrPathName.push_back( dlg.GetNextPathName(mPos) );
}
}
接着看看如果不改动的话,对有规律的文件如1.txt、2.txt等文件,同时打开时读入的次序是什么样的?当然不会是以鼠标选择的时间次序。看看这个实验吧:假如有1~5.txt五个文本文件,我任意选择,将文件路径都保存下来看看先后次序吧,其实从打开栏中就可以看到先后的顺序了。做三个实验吧:
实验一、
假如我按照这样的先后顺序选择:
2.txt 4.txt 5.txt 3.txt 1.txt
那么程序会以什么顺序读取呢?如下图:
实验二、
假如我这样按这样的先后顺序选择(按住ctrl键进行多个文件选择):
1.txt 2.txt 4.txt 3.txt 5.txt
那么程序会以什么顺序读取呢?如下图:
在文件名一栏中会显示顺序,果然不是按照选择的顺序排列的。
实验三、
假如我按照鼠标点击的先后顺序这样选择:
1.txt 5.txt 2.txt 4.txt 3.txt
那么程序会以什么顺序读取呢?如下图:
总结上面三幅示意图,规律出来了,对于上面所说的比较有规律或者说具有可比较文件名的文件来说,有以下的四个规律:
1. 鼠标最后选择的总是在最前面(我说的是文件名中显示的最前面);
2. 如果鼠标最后选择的文件名(除去扩展名即12345)与其它选择的文件相比较(如果可比较,实际上也是可以比较的,见MFC字符串的比较函数,上面的例子中我们认为是对12345的数值进行比较),结果最后选择的文件名比前面选择的都要小的话,程序会对其后的文件名按照可比较的原则(如整数按大小,字符串按长度)进行从“小”到“大”的排序(小和大是广义的),这样的结果是对鼠标选择的所有文件都按从小到大的顺序排列,如实验一所示;
3. 如果鼠标最后选择的文件名比之前选择的文件名都要大,程序会对其后的文件名按照可比较大原则进行从“小”到“大”的排序,这样,除了最后选择的文件之外,之前的所有文件都按照顺序排序。如实验二所示;
4. 如果鼠标最后选择的文件名处于之前选择的文件名的中间,那么程序会以最后选择的文件名作为开始,将比它大的所有文件按照顺序排在其后,这一段排完之后再考虑比最后文件名小的文件的排序。如实验三所示;
为了理解上面所说的可比较的原则,设计这样的两组文件说上面的实验
第一组:a.txt b.txt c.txt d.txt e.txt
实验一、
鼠标选择顺序:b.txt c.txt e.txt d.txt a.txt
程序排列顺序:
实验二、
鼠标选择顺序:c.txt d.txt b.txt a.txt e.txt
程序排列顺序:
实验三、
鼠标选择顺序:d.txt e.txt b.txt a.txt c.txt
程序排列顺序:
第二组:a.txt aa.txt aaa.txt aaaa.txt aaaaa.txt(只能看到四个文件名,看不到的就是最后一个)
实验一、
鼠标选择顺序:aa.txt aaaa.txt aaa.txt aaaaa.txt a.txt
程序排列顺序:
实验二、
鼠标选择顺序:aaaa.txt a.txt aaa.txt aa.txt aaaaa.txt
程序排列顺序:
实验三、
鼠标选择顺序:aaaaa.txt a.txt aaaa.txt aa.txt aaa.txt
程序排列顺序:
大部分的文件名都是字符串或者是字符串和数字的组合,当然本文所指的是文件名有一定规律的文件(一般是由程序自动生成的),如果对更复杂的文件名,微软的函数当然也按照一定的规则进行排序如首先比较长度,长度相等比较字符在字母表中的顺序等等,当然对复杂的文件名进行排序的意义不大。本文之所以要排序,是因为在后继工作中需要按照文件名从小到大的顺序读取文件内容。因此,我设计了如下的代码进行文件名的排序:
const CString m_cstrPrefix( "StrLig" );
void COpenMultiFileView::OnFileOpen()
{
CFileDialog dlg(TRUE,"","*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT);
CString strBuf("", 20000);
dlg.m_ofn.lpstrFile = strBuf.GetBuffer(20000);
strBuf.ReleaseBuffer();
vector<CString> vStrPathName;
CString *pStrPathName;
if(dlg.DoModal()==IDOK)
{
POSITION mPos = dlg.GetStartPosition();
while(mPos!=NULL)
{
vStrPathName.push_back( dlg.GetNextPathName(mPos) );
}
int nSize = vStrPathName.size();
pStrPathName = new CString[nSize];
//对文件名数组进行排序
FilePathRanking( vStrPathName, pStrPathName, m_cstrPrefix );
CString str(" ");
for( int i = 0; i < vStrPathName.size(); i++ )
{
str = str + pStrPathName[i] + "/n";
}
MessageBox( str );
}
else
{
return;
}
}
void COpenMultiFileView::FilePathRanking( vector<CString>& vStr, CString *pStr, const CString strPrefix )
{
vector<CString>::size_type st = vStr.size();
for( int i = 0; i < st-1; ++i )
{
for( int j = 0; j < st-i-1; ++j )
{
CString strFileName1 = vStr[j].Right( vStr[j].GetLength() - vStr[j].ReverseFind('//')-1 );
CString strFile1 = strFileName1.Left( strFileName1.Find('.') );
CString strFlag1 = strFile1.Right( strFile1.GetLength()-strPrefix.GetLength() );
int nFlag1 = atoi( strFlag1 );
CString strFileName2 = vStr[j+1].Right( vStr[j+1].GetLength() - vStr[j+1].ReverseFind('//')-1 );
CString strFile2 = strFileName2.Left( strFileName2.Find('.') );
CString strFlag2 = strFile2.Right( strFile2.GetLength()-strPrefix.GetLength() );
int nFlag2 = atoi( strFlag2 );
if( nFlag1 > nFlag2 )
{
CString strTemp = vStr[j];
vStr[j] = vStr[j+1];
vStr[j+1] = strTemp;
}
}
}
for( int k = 0; k < st; ++k )
{
pStr[k] = vStr[k];
}
}
需要说明的是上面这段代码仅仅针对文件名中有特定规律如字符相同,以数字来标识的文件名。因此m_cstrPrefix变量就很重要,它是指文件名中除了数字之外的字符。如本文的实验文件名为StrLigX.txt,则m_cstrPrefix为StrLig,如果是常规的1234命名,m_cstrPrefix可设为空。为了检验代码,将排序后的文件和路径名输出显示:
结果如下:
代码还存在一些问题,比如,如果文件名太长,读取的文件超过一定数目程序就会报错,因此我将文件名都改成缩写的。