檔案傳送常用的三種方式:FTP、Email及“網路位置”,都在一定程度上實現了檔案資料的交流,但它們都主要面向“點對點”的傳送,無法實現“一塊空間,資源互見”的應用需求,這種基於“點對多”的共用模式需要尋求另外的傳輸途徑,網路硬碟就是一種很好的解決方式。
常用傳輸方式及其在特定環境下面臨的困難
我們經常有這樣的應用需求:通過網路交換公用資料檔案以實現資源共用,同時保護私人資料不被非法訪問,並使用簡單、直觀的方式操作。我們常用的檔案傳輸FTP、Email郵件、網路位置都能實現檔案的傳送。其中,"Ftp"功能最為強大,但使用起來卻稍顯複雜,一大堆設定足以讓許多人望而止步,尤其使用者數量不可預見時,針對特殊需求使用者的設定將更加繁瑣;"Email"是大家所熟悉的了,但它的傳送不僅需要你連入Internet,而且它的安全性也是個問題,在企業內部,財務、勞資等檔案資料需通過這種方式交流不是好辦法;"網路位置"是又一種傳送檔案的方法,通過在本機上指定共用的Web檔案夾並放置資源檔,一定範圍內的使用者可以訪問到這些檔案,然而這種方式使用的範圍相當有限,通常在同一個DNS段地址內的使用者才能順利訪問,其它尤其是Internet上的使用者,很難使用,此外同Email類似,它的使用也不直觀,很多時候你不得不在許多列表電腦上一層層展開搜尋才有可能擷取你想要的資源!
由此看來,以上三種方式雖然在一定程度上實現了檔案資料的交流,但它們都主要面向"點對點"的傳送(你只能被動地等對方放置資料而不能主動"可視化"地索取),無法實現"一塊空間,資源互見"的應用需求,這種基於"點對多"的共用方式需要尋求另外的傳輸途徑,網路硬碟就是一種很好的解決方式。
網路硬碟的優勢
網路硬碟(也稱共用空間),是伺服器上的一塊硬碟空間,在這裡,如果你具備足夠的許可權,你可以對它隨意操作,就象使用你的本機電腦一樣。要知道,這一切以Http的方式傳輸,以Web的形式展現在所有使用者面前,通過瀏覽器這種熟悉的方式訪問,這樣,"一塊空間,資源互見"的共用模式得以實現!
此外,網路硬碟介面在用戶端運行,它允許使用者提交資料到伺服器,然後在指定的範圍內管理這些資訊,這種處理模式大量使用在實際開發中,尤其是在構建互動式網路文件管理系統方面:網上考試系統、檔案傳輸系統、新聞發布系統以及公司競標系統等方面都有大量應用!
以下使用ASP.net(Visual C#語言實現)和XML(可延伸標記語言 (XML))開發了這樣的網路硬碟系統。關於程式的開發細節及代碼中使用的關鍵技術和痛點,都有詳細的講解,參照這些說明,你完全可以開發出自己的網路硬碟。
網路硬碟實現的功能
我們的網路硬碟實現了以下功能:
1、查看檔案夾內容
2、建立新檔案夾同時可設定存取權限
3、檔案夾間的跳轉:進入下一級,返回上一級
4、上傳檔案到指定檔案夾
5、下載檔案到本機或線上查看檔案內容
6、刪除檔案或檔案夾
開發細節及技術關鍵點
1、查看檔案夾內容:
程式一開始將進入指定的根資料夾(如\NetHard),這個檔案夾下的內容將通過資料繫結控制項(DataGrid)來列表顯示,包括以下方面:類別(區別檔案夾或檔案)、名稱、許可權(是否允許進入檔案夾?是否可以下載檔案?)、刪除(是否允許刪除檔案或檔案夾?)以及針對檔案夾的建立者。這裡,由於檔案夾中內容動態變化(你不知道什麼時候就有使用者傳送了檔案或建立了檔案夾或刪除了它們),我們通過動態建立資料表DataTable來讀取指定檔案夾下的內容, 然後作為資料來源與顯示控制項DataGrid綁定,這樣,資料的顯示就總是適時的。建立動態表的函數如下:
public DataTable Bind(string fullFoldERPath)//建立資料表讀取檔案夾內容
{
//以下是動態建立資料表的方法
DataTable dt=new DataTable();
DataRow dr;
//首先建立資料表結構
dt.Columns.Add(new DataColumn("type",System.Type.GetType("System.String")));//類型
dt.Columns.Add(new DataColumn("name",System.Type.GetType("System.String")));//名稱
dt.Columns.Add(new DataColumn("action",System.Type.GetType("System.String")));//操作
dt.Columns.Add(new DataColumn("owner",System.Type.GetType("System.String")));//建立人
//為每一行填充資料
foreach(string d in Directory.GetFileSystemEntries(fullFolderPath)){
dr=dt.NewRow();//建新行
string[] parts=d.Split(new char[]{'\\'});
string txt=parts[parts.Length-1];//取最後一部分的字串,它將可能是檔案名稱或檔案夾
dr[1]=txt;//名稱name
if(File.Exists(d))//如果是檔案
{
dr[0]="檔案";//類型type
int pos=currFullPath.IndexOf("NetHard");
string relaUrl=currFullPath.Substring(pos);
string
url="http://10.80.50.1/SharedSpace/"+relaUrl+"/"+txt;//
10.80.50.1為作者伺服器位址,你應該將它修改為你所在伺服器位址
dr[2]="<a href="+url+" target=_blank"+">下載</a>";
}
else if(Directory.Exists(d)){//如果是檔案夾
dr[0]="檔案夾";//type類型
string password=GetFolderPassword(d);//取得檔案夾密碼資訊
int type=GetFolderLimitType(d);
if((password!="no")&&(type!=1))
dr[2]="<a
href=PasswordValidate.ASPx?path="+d+">密封</a>";//操作action
else
dr[2]="<a href=Default.aspx?path="+d+">進入</a>";//操作action
dr[3]=GetFolderOwner(d);//取檔案夾建立者名
}
else
Response.Write("<script>alert('無對象可綁定!')</script>");
dt.Rows.Add(dr);//添加行
return dt;//返回資料表
}
}
這個方法取出指定檔案夾下的內容分別處理:如果是檔案,就顯示"下載"連結指向伺服器上檔案的Url地址;對檔案夾需要視保護與否及保護類型進一步區別處理:若"進入受限"則顯示"密封"匯入到密碼驗證頁,"進入不受限"時修改查詢字串,顯示"進入"連結指向初始顯示頁。
2、建立新檔案夾及設定存取權限:
輸入新檔案夾名後,你就可以在當前路徑下建立新的檔案夾,ASP.NET下遠程建立新檔案夾和在本地機操作完全一樣,非常的簡單,.net的IO名字空間提供了專門的類庫Directory,通過調用其方法就可以實現,語句如下:
Directory.CreateDirectory(string directory)
其中,字串directory表示建立檔案夾的完整路徑,這個方法預設向所有使用者開放新檔案夾的完全讀寫存取權限。特殊地,對網路硬碟共用根資料夾(程式中樣本為"NetHard"檔案夾,你可以更改它)的建立你還可以手動進行,對應地,你需要手動設定以開放此檔案夾的寫入許可權,在IIS下,你可以在"internet資訊服務"下,對該檔案夾執行"許可權嚮導"來設定存取權限。
資源共用時應該考慮安全性。這裡,你可以設定使用者對該檔案夾的存取權限,通過設定密碼,你可以指定是否允許使用者進入該檔案夾,是否允許刪除該檔案夾,或者兩者都禁止。這樣,你可以保護自己的檔案,將它們獨佔訪問或者限制在一個特定的範圍內(這個範圍的成員應該知道你的密碼),這樣,產品研發部門可以共用一個檔案夾,財務部門也通過同樣的方式共用另一個檔案夾,不屬於這個部門的人員將限制訪問。當然,這樣的限制你也可以應用到單個檔案上(這樣的應用似乎不多,程式未實現)。
此外,為了管理這些檔案夾,你需要保留它們的設定資訊:檔案夾名、位置、受限操作類型、密碼及建立人等。程式中將這些資訊寫入一XML檔案(此為folder.XML檔案),隨後對檔案夾的各種管理操作均通過讀寫該xml檔案來進行,以下方法就實現了建立檔案夾時設定資訊的儲存:
public void CreateXmlOrAddFrag(string xmlFullPath,string
folderFullPath,string owner,string password,int type){
XmlDocument xmlDoc=new XmlDocument();
string xml="";
string xmlNode="<character>";
xmlNode+="<fullPath>";
xmlNode+=folderFullPath;
xmlNode+="</fullPath>";
xmlNode+="<owner>";
xmlNode+=owner;
xmlNode+="</owner>";
xmlNode+="<password>";
xmlNode+=password;
xmlNode+="</password>";
xmlNode+="<type>";
xmlNode+=type;
xmlNode+="</type>";
xmlNode+="</character>";
if(!File.Exists(xmlFullPath)){//不存在則建立xml隱藏檔
xml="<?xml version='1.0' encoding='gb2312'?>";
xml+="<folder>";
xml+=xmlNode;
xml+="</folder>";
xmlDoc.LoadXml(xml);
xmlDoc.Save(xmlFullPath);//隱藏檔
}
else{//存在xml隱藏檔則添加新的文檔片段
xmlDoc.Load(xmlFullPath);
XmlDocumentFragment
docFrag=xmlDoc.CreateDocumentFragment();//文檔片元素節點
docFrag.InnerXml=xmlNode;
XmlNode currNode=xmlDoc.DocumentElement;//擷取文檔根節澱
currNode.InsertBefore(docFrag,currNode.FirstChild);//插入文檔段
xmlDoc.Save(xmlFullPath);//儲存改變
}
}
其中,參數fileFullPath是隱藏檔夾資訊的xml檔案路徑,folderFullPath是此新檔案夾路徑,owner是建立人名,password是密碼,type表示限制操作的類型("0"表示進入受限,"1"表示刪除受限)。在程式運行之初,隱藏檔夾資訊的folder.xml檔案可能尚不存在,所以程式中首先判斷這個檔案是否存在,不存在則動態建立這個檔案,這之後建立檔案夾時,將只需要添加文檔片段。這裡,對Xml檔案的讀寫通過DOM(文件物件模型)來實現,由於此處Xml檔案不會太大,這種方式不會對記憶體資源要求太高,速度也會很快!
ASP.NET+XML打造網路硬碟 (3)
3、對檔案及檔案夾的操作:
對檔案的操作包括"下載"和"刪除"兩種,在上面列表顯示指定檔案夾中內容時,針對檔案,有這樣的語句:
dr[2]="<a href="+url+" target=_blank"+">下載</a>";//建立聯結地址
其中,url是指定檔案對應的伺服器路徑。 通過這樣的連結將檔案定位到伺服器上的對應位置。視檔案格式的不同,用戶端可以下載檔案到本機上,也可以就在伺服器上開啟它。
刪除檔案很簡單,.net的IO命名空間的File類庫有這樣的方法:
File.Delete(string filename);其中,filename為檔案的完整路徑
你需要注意的是,檔案的刪除將不需要驗證,要防止檔案被刪除,你需要依照下面的方式來進行。(當然,程式中為避免檔案誤刪除提供了確認驗證,檔案夾刪除也一樣!)
對檔案夾的操作分為:進入或者刪除。如果檔案夾在建立時被設定"進入受限"或者"刪除受限",使用者在執行這樣的操作時將被要求密碼驗證,只有通過驗證才能完成相應的操作,這種方式保護了你的檔案被非法訪問或刪除。
相對檔案的刪除,檔案夾的刪除程式要稍微複雜些,.Net的Directory類庫提供的方法Delete()只能刪除空檔案夾,這就需要我們首先清空檔案夾中內容,然後才能完成這一操作,由於檔案夾中還可能再包含有檔案夾,我們通過遞迴調用來實現這一操作:
//刪除檔案夾的方法
public void DeleteFolder(string dir)
{
foreach(string d in Directory.GetFileSystemEntries(dir))
{
if(File.Exists(d))
File.Delete(d);//直接刪除其中的檔案
else
DeleteFolder(d);//遞迴刪除子檔案夾
}
Directory.Delete(dir);//刪除已空檔案夾
}
其中,參數dir是待刪除檔案夾的完整路徑。程式使用迴圈語句,尋找檔案夾中的內容,是檔案則直接刪除,如果是檔案夾,則遞迴調用方法自身來刪除子檔案夾,檔案夾清空後再完成刪除操作。
4、檔案上傳:
要實現網路硬碟的功能,必須要有可供操作的檔案,這些檔案來自於用戶端的上傳(當然,伺服器端也能提供這些檔案,但這不是網路硬碟的重點),過去我們實現檔案的上傳,在ASP中通常是使用第一些檔案上傳組件,比如Microsoft 的PostingAcceptor組件,另外還有第三方提供的一些付費組件(不過說真的,這些組件並不好用)。那時候想要自己開發這樣的檔案上傳組件,相當繁瑣;而現在,.Net提供的類庫HttpPostedFile和HttpFilesCollection可以很容易地訪問上傳到伺服器的檔案,同時使開發人員控制檔案上傳過程。其中的HttpPostedFile類封裝已經上傳到伺服器的檔案對象,其方法和屬性提供對每個檔案的內容和屬性的訪問;HttpFileCollection類則為多個HttpPostedFile對象提供一個容器,用作儲存上傳給伺服器的資料結構的類,這樣你就可以利用被傳送的檔案集合,該檔案集合可通過其Files屬性從HttpRequest 對象訪問,一旦伺服器接收了請求的整個內容,該集合就可以訪問。這些內建的組件使得ASP.NET中實現檔案上傳相當容易,甚至只需要幾行代碼就可以了!關於Asp.net中實現檔案上傳的文章很多,這裡不做專門的闡述,需要的話你可以參考那些文章,這裡,只提示你需要注意以下幾點:
1)、用戶端表單的編碼類別型Enctype 設定為multipart/form-data的MIME格式,提交表單使用Http的post方法,象下面這樣:
<form id="form1" method="post" enctype="multipart/form-data/form-data"
runat="server" >
2)、HttpInputFile控制項運行在伺服器端,設定runat=server,type=file ,象下面這樣:
<INPUT id="fileUp" type="file" size="6" runat="server">
3)、要上傳多個檔案,你可以布置多個HttpInputFile控制項,然後使用HttpRequest.Files來擷取這些檔案。
5、環境設定檔Web.config的處理:
在中文狀態下,你可能需要將全球化設定編碼由預設的"Utf-8"改為"gb2312",語句如下:
<globalization
requestEncoding="gb2312"
responseEncoding="gb2312"
/>
同時,Web.config預設設定的的檔案大小限制可能並不能滿足你的需要,你或許需要將限制尺度放大一些。這通過修改參數maxRequestLength的值來實現,如下所示:
<!-- 設定可接受的最大位元組數 -->
<httpRuntime maxRequestLength="500000">
</httpRuntime>
6、隨時跟蹤"當前路徑"值:
程式中的另一個關鍵點是關於"當前路徑"的,由於你總是需要在不同的檔案夾之間跳轉:點擊"進入"到達下一級檔案夾,點擊"上一級檔案夾"返回前一級檔案夾;而所有這些檔案夾的內容都通過同一個頁面(Default.aspx)來顯示,這個顯示頁面被設定為始終顯示當前檔案夾下內容。在你傳送查詢字串來調用它時,你需要在查詢字串中包含當前路徑的完整表示,這在程式中通過設定一個靜態變數來實現:public static string currFullPath=""; 當前路徑發生改變時,總是將這個路徑值傳送給這個靜態標量:
currFullPath=Request["path"];這就使得這個靜態變數始終儲存著當前的路徑值,以這個靜態變數為查詢字串調用顯示頁: Response.Redirect("Default.aspx?path="+currFullPath)就總能顯示當前檔案夾下的內容了!
參考資料:
《Asp.net程式員參考手冊》、《XML進階編程》、《C#進階編程》、微軟MSDN
運行環境:
程式在:Windows XP中文正式版、.Net Frameworks 正式版、Visual Studio.Net中文正式版下調試通過,在區域網路(總部+多個異地子公司模式)上穩定運行