FTP伺服器LIST指令獲取的檔案列表資訊解析(UNIX格式)
最近在寫FTP客戶端的程式,但是在傳送LIST指令之後,不知如何解析伺服器發回的列表資訊,上網一查,略坑,居然都是同一篇文章,居然還都是原創,而且對於UNIX格式下的檔案列表資訊並沒有解析完成,因為沒有判斷出檔案的年份,附帶的程式也不完善。
經過幾翻查詢資料,終於知道了正確的解析方法,與各位同道一起分享,請各位指正。
FTP伺服器執行的系統一般分為windows和UNIX作業系統,系統不一樣,FTP伺服器返回的資訊也不一樣,有兩種格式,如下:
1、MS-DOS檔案列表格式解析:
這種格式的講解就略過了,百度很容易就找到了。
2、現在看UNIX檔案列表格式的解析:
UNIX檔案列表格式解析:
drwx----- 1 user group 0 Sep 20 18:50 360Rec
-rwx------ 1 user group 24 Jun 11 2009 autoexec.bat
drwx----- 1 user group 0 Jul 14 2009 Documents and Settings
drwx----- 1 user group 0 Feb 08 2013 User
drwx----- 1 user group 0 Jun 28 22:16 Users
以上是我在程式設計時伺服器返回的部分檔案列表資訊。
UNIX檔案列表每一個檔案資訊分為9個部分,現在說每個部分代表的意義:
第一部分drwx-----,共9個字元,第一個字元d表示該檔案是目錄,-表示是檔案,之後的r表示可讀,w表示可寫,x表示可執行
第二部分,第二部分,第三部分,對我來說意義不大,略過不提
第五部分:如果是目錄,則為0(<DIR>),如果是檔案,則為檔案大小
第六部分:檔案的月份
第七部分:檔案的月份的某一天
第八部分:或者為小時分鐘,或者為年份
第九部分:檔名
資訊提取方式,以提取第一部分資訊為例:
CString msg = "drwx----- 1 user group 0 Sep 20 18:50 360Rec",str; msg.TrimLeft();//去掉左側的空格,製表符,回車 int n = msg.Find(" ");//查詢第一個空格,返回空格的位置,或者-1 str = msg.Left(n);//將msg中第n個位置左側的字元賦值給str,提取了第一部分資訊 msg = msg.Mid(n+1);//將msg中第n個位置之後的所以字元賦值給msg
迴圈解析……,即可得到所有部分的資訊。
現在說檔案時間資訊的處理:
我想大家應該在糾結第八部分如何處理,如何得到具體的年份,如果第八部分為年份,自然萬事大吉,如果不是年份,我們怎麼得到年份呢?其實檔案列表資訊是有具體規定的。我們再處理時間時,必須與當前的時間進行比較,這裡的當前時間是指:程式的執行的具體時間。
如果第八部分為HH:MM(H:小時,M:分鐘)格式,獲取當前時間的年year、月month和日day(2014年3月3日),比較檔案列表中的月份和當前月份,比如第一個檔案列表資訊中的月份是Sep,9月大於當前月份3月,那麼該檔案的年份就是當前年份-1,即是2013年;如果小於當前月份,那麼該檔案的年份就是當前年份。
這樣就算第八部分是HH:MM,我們也能得到檔案的年份了。
以下是我的解析函式:
while(1)//處理整個檔案列表資訊
{//整個檔案列表資訊中,每個檔案資訊是以"\r\n"來隔開的
n = st.Find("\r\n");//查詢st中第一個"\r\n"的位置
if(n == -1)//若不存在,則結束迴圈
break;
filelist = st.Left(n);//將st中從0開始到第一個"\r\n"的字串賦值給filelist,即第一個檔案資訊
st = st.Mid(n+2);//將st從第一個"\r\n"的位置開始,到結束的字元賦值給st,即保留剩餘檔案資訊
if(filelist[0] == 'd')
{
//若為目錄,相應處理程式
}
else
{
//若為檔案,相應處理程式
}
}
CString GetSegmentInfo(CString sFileInfo,int nSegment)//分割檔案資訊,第一個形參是某個檔案的資訊,第二個形參是提取的第幾部分,從0開始,到8結束
{
int nIdx = -1;
int nSeg = 0;
CString sInfo = "";
sFileInfo.TrimLeft();//消除前導的空格,製表符,換行符
while(nSeg < nSegment+1)//逐段切隔
{
nIdx = sFileInfo.Find(" ");//以空格為切隔
sInfo = sFileInfo.Left(nIdx);
if(nSeg < nSegment)//檔名有空格時也可以分割出來
sFileInfo = sFileInfo.Mid(nIdx+1);//如果提取的是檔名,最後一次Mid不能執行,否則當檔名中有空格時,得到的檔名不對
sFileInfo.TrimLeft();//過濾左側的空格符
nSeg++;
}
if(nSegment == 8)
sInfo = sFileInfo;
return sInfo;
}
CString GetTime(CString month,CString day,CString tt)//解析檔案的年月日
{
CString mon[12] ={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"},filetime;
CTime _time=time(NULL);
int mm = 0,year,dd = atoi(day);
for(int i = 0;i < 12; i++)
{
if(month == mon[i])
{
mm = i+1;//取得檔案資訊中的月份
break;
}
}
if(tt.Find(':') == -1)//如果第八部分中沒有字元':',則第八部分是年份
year = atoi(tt);
else//如果不是年份
{
if(mm > _time.GetMonth())//若大於當前月份,則年份為當前年份-1
year = _time.GetYear()-1;
else//否則為當前年份-1
year = _time.GetYear();
}
filetime.Format("%d/%d/%d",year,mm,dd);
return filetime;
}