要使用網站上傳文件,在asp.net的范疇,我基本上能想到的有兩類,一類是通過HTTP POST請求獲得文件信息,另外一類是通過WebService或者WCF之類的技術對外發布服務。
以前做3G攝像頭項目的時候,做過使用HTTP POST的方式獲得照片,方式很簡單,就是一個aspx文件(其實用asp也行,最開始是用asp實現的,用aspx的時候還出了點幺蛾子),只是客戶端(攝像頭)那邊需要了解POST請求,將圖片做成數據傳輸上來。這個方式也沒什么不好的,就是無奈在集成到系統中的時候總是出點問題,想著反正還要做多種客戶端,于是乎改成第二類方式。
需求是要能夠實現多個平臺(PC,Android,iOS)的文件傳輸。
我說用WCF吧,之前我用來著,容易上手,但是其他人覺得WCF可能不太容易與非.NET平臺互通(沒深入探究,但是網上看到過有人用android調用WCF的,以后有時間再探討),于是乎老老實實的用WebService。
Android調用webservice好像也有兩種方式,我們實現的是用ksoap2調用,首先我需要編寫WEBSERVICE。
文件用什么參數傳遞呢?
這里有序列化的知識,我還沒深入體會,說說自己的看法吧:
首先序列化個人看來就是把對象什么的變得可以存儲和傳輸,有了這個就能夠很方便的實現一些網絡應用。然后就是說KSOAP2對基本的數據類型都能夠序列化,我看到string了,但是也不知道支持還是不支持byte[]型。
回到正題,干脆2個都來吧,反正也不差多少事。
由于自己有點疑慮,所以先實現了第二種,通過某種方式---base64編碼解碼。通過這個編碼可以將BYTE變成能夠直接網絡傳輸的string,server端收到數據之后解碼就能夠得到原始byte[]。以下列出web端函數。
[WebMethod(MessageName = "UploadSmallString")] public bool UploadSmallString(string fileName, string serializedData) { try { byte[] receivedBytes = Convert.FromBase64String(serializedData); using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, Fileaccess.ReadWrite, FileShare.ReadWrite)) { fs.Write(receivedBytes, 0, receivedBytes.Length); } return true; } catch { return false; } }
客戶端用base64編碼就可以了,網上找找很多。細心的客官可能看到函數名SmallString,對的,這個適用于文件不太大的時候傳輸,傳輸很大的文件呢?
分塊!分塊傳輸的好處在于能夠支持斷點續傳,說說客戶端的實現思路:
然后服務器端呢,寫個重載吧,可是試了試不成功,參見http://www.49028c.com/menglin2010/archive/2012/03/29/2421445.html中說不太支持,要改,用[WebServiceBinding(ConformsTo = Wsiprofiles.BasicPRofile1_1)]如果改成None用以支持重載的話,又怕出現兼容性問題,老老實實的吧還。
/// <summary> /// 使用BASE64編碼接收分塊傳輸的大文件 /// </summary> /// <param name="fileName">文件名</param> /// <param name="serializedData">BASE64數據</param> /// <param name="blockSerial">用以識別文件塊的ID</param> /// <returns>對應成功文件塊ID,不成功便成-1</returns> [WebMethod(MessageName = "UploadBlobString", Description = "支持大文件傳輸的方法,blockserial為0將創建新文件,這也是默認行為")] public int UploadBlobString(string fileName, string serializedData, int blockSerial = 0) { try { byte[] receivedBytes = Convert.FromBase64String(serializedData); if (blockSerial == 0) { using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Create)) { fs.Write(receivedBytes, 0, receivedBytes.Length); } } else { using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Append)) { fs.Write(receivedBytes, 0, receivedBytes.Length); } } return blockSerial; } catch { return -1; } }
琢磨了一下,好像這個完全可以替代前一個方法,是用.NET默認參數的特性,指定blockSerial默認為0。如果客戶端中斷了,續傳的時候從斷點blockSerial開始就OK了。
接下來說說第一種,使用bye[]的方式。
[WebMethod(MessageName = "UploadSmallByte", Description = "直接發送BYTE數組存儲")] public bool UploadSmallByte(string fileName, byte[] fileBytes) { try { using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) { fs.Write(fileBytes, 0, fileBytes.Length); } return true; } catch { return false; } }
這種方式我沒怎么測試過,但是有一個有意思的事情,就是如果ANDROID編碼BASE64后的string直接傳遞給byte[]參數,這個函數依然可以正常工作,上傳的圖片還是可以正常顯示,很是詭異呀,想在.net下試一試,直接由于類型不同,不能編譯,以后有機會再琢磨琢磨。
P.S. BASE64方式的代碼經過測試能夠在ANDROID平臺和PC平臺下通過,iOS等待BASE64實現(貌似沒有內部的BASE64編碼方法),從原理上應該沒問題,歡迎大家討論。
新聞熱點
疑難解答