大型網站架構:下降主站服務器的壓力
CDN:智能DNS挑選最近的服務器提供圖片等
雲存儲:把圖片放到單獨的服務器,價格低html
雲存儲:七牛、AWS、又拍雲、盛大雲、阿里雲、百度雲
雲計算:租、按需使用、按需付費api
又拍雲:賬號註冊--操做空間
上傳:
ftp:// 登陸
http:// 下載SDK
問題:把上傳的文件不存在當前應用程序某個文件夾下,而是直接存到雲存儲,並返回一個雲服務器的路徑 ---???數組
步驟:註冊-ftp上傳-http上傳(下載SDK-demo示例)-保存到雲上、返回雲路徑服務器
public class UpYun { private string bucketname; private string username; private string password; private bool upAuth = false; private string api_domain = "v0.api.upyun.com"; private string DL = "/"; private Hashtable tmp_infos = new Hashtable(); private string file_secret; private string content_md5; private bool auto_mkdir = false; public string version() { return "1.0.1"; } /** * 初始化 UpYun 存儲接口 * @param $bucketname 空間名稱 * @param $username 操做員名稱 * @param $password 密碼 * return UpYun object */ public UpYun(string bucketname, string username, string password) { this.bucketname = bucketname; this.username = username; this.password = password; } /** * 切換 API 接口的域名 * @param $domain {默認 v0.api.upyun.com 自動識別, v1.api.upyun.com 電信, v2.api.upyun.com 聯通, v3.api.upyun.com 移動} * return null; */ public void setApiDomain(string domain) { this.api_domain = domain; } /** * 是否啓用 又拍簽名認證 * @param upAuth {默認 false 不啓用(直接使用basic auth),true 啓用又拍簽名認證} * return null; */ public void setAuthType(bool upAuth) { this.upAuth = upAuth; } private void upyunAuth(Hashtable headers, string method, string uri, HttpWebRequest request) { DateTime dt = DateTime.UtcNow; string date = dt.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'", CultureInfo.CreateSpecificCulture("en-US")); request.Date = dt; //headers.Add("Date", date); string auth; if (request.ContentLength != -1) auth = md5(method + '&' + uri + '&' + date + '&' + request.ContentLength + '&' + md5(this.password)); else auth = md5(method + '&' + uri + '&' + date + '&' + 0 + '&' + md5(this.password)); headers.Add("Authorization", "UpYun " + this.username + ':' + auth); } private string md5(string str) { MD5 m = new MD5CryptoServiceProvider(); byte[] s = m.ComputeHash(UnicodeEncoding.UTF8.GetBytes(str)); string resule = BitConverter.ToString(s); resule = resule.Replace("-", ""); return resule.ToLower(); } private bool delete(string path, Hashtable headers) { HttpWebResponse resp; byte[] a = null; resp = newWorker("DELETE", DL + this.bucketname + path, a, headers); if ((int)resp.StatusCode == 200) { resp.Close(); return true; } else { resp.Close(); return false; } } private HttpWebResponse newWorker(string method, string Url, byte[] postData, Hashtable headers) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://" + api_domain + Url); request.Method = method; if (this.auto_mkdir == true) { headers.Add("mkdir", "true"); this.auto_mkdir = false; } if (postData != null) { request.ContentLength = postData.Length; request.KeepAlive = true; if (this.content_md5 != null) { request.Headers.Add("Content-MD5", this.content_md5); this.content_md5 = null; } if (this.file_secret != null) { request.Headers.Add("Content-Secret", this.file_secret); this.file_secret = null; } } if (this.upAuth) { upyunAuth(headers, method, Url, request); } else { request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new System.Text.ASCIIEncoding().GetBytes(this.username + ":" + this.password))); } foreach (DictionaryEntry var in headers) { request.Headers.Add(var.Key.ToString(), var.Value.ToString()); } if (postData != null) { Stream dataStream = request.GetRequestStream(); dataStream.Write(postData, 0, postData.Length); dataStream.Close(); } HttpWebResponse response; try { response = (HttpWebResponse)request.GetResponse(); this.tmp_infos = new Hashtable(); foreach (var hl in response.Headers) { string name = (string)hl; if (name.Length > 7 && name.Substring(0, 7) == "x-upyun") { this.tmp_infos.Add(name, response.Headers[name]); } } } catch (Exception e) { throw e; } return response; } /** * 獲取整體空間的佔用信息 * return 空間佔用量,失敗返回 null */ public int getFolderUsage(string url) { Hashtable headers = new Hashtable(); int size; byte[] a = null; HttpWebResponse resp = newWorker("GET", DL + this.bucketname + url + "?usage", a, headers); try { StreamReader sr = new StreamReader(resp.GetResponseStream(), Encoding.UTF8); string strhtml = sr.ReadToEnd(); resp.Close(); size = int.Parse(strhtml); } catch (Exception) { size = 0; } return size; } /** * 獲取某個子目錄的佔用信息 * @param $path 目標路徑 * return 空間佔用量,失敗返回 null */ public int getBucketUsage() { return getFolderUsage(""); } /** * 建立目錄 * @param $path 目錄路徑 * return true or false */ public bool mkDir(string path, bool auto_mkdir) { this.auto_mkdir = auto_mkdir; Hashtable headers = new Hashtable(); headers.Add("folder", "create"); HttpWebResponse resp; byte[] a = new byte[0]; resp = newWorker("POST", DL + this.bucketname + path, a, headers); if ((int)resp.StatusCode == 200) { resp.Close(); return true; } else { resp.Close(); return false; } } /** * 刪除目錄 * @param $path 目錄路徑 * return true or false */ public bool rmDir(string path) { Hashtable headers = new Hashtable(); return delete(path, headers); } /** * 讀取目錄列表 * @param $path 目錄路徑 * return array 數組 或 null */ public ArrayList readDir(string url) { Hashtable headers = new Hashtable(); byte[] a = null; HttpWebResponse resp = newWorker("GET", DL + this.bucketname + url, a, headers); StreamReader sr = new StreamReader(resp.GetResponseStream(), Encoding.UTF8); string strhtml = sr.ReadToEnd(); resp.Close(); strhtml = strhtml.Replace("\t", "\\"); strhtml = strhtml.Replace("\n", "\\"); string[] ss = strhtml.Split('\\'); int i = 0; ArrayList AL = new ArrayList(); while (i < ss.Length) { FolderItem fi = new FolderItem(ss[i], ss[i + 1], int.Parse(ss[i + 2]), int.Parse(ss[i + 3])); AL.Add(fi); i += 4; } return AL; } /** * 上傳文件 * @param $file 文件路徑(包含文件名) * @param $datas 文件內容 或 文件IO數據流 * return true or false */ public bool writeFile(string path, byte[] data, bool auto_mkdir) { Hashtable headers = new Hashtable(); this.auto_mkdir = auto_mkdir; HttpWebResponse resp; resp = newWorker("POST", DL + this.bucketname + path, data, headers); if ((int)resp.StatusCode == 200) { resp.Close(); return true; } else { resp.Close(); return false; } } /** * 刪除文件 * @param $file 文件路徑(包含文件名) * return true or false */ public bool deleteFile(string path) { Hashtable headers = new Hashtable(); return delete(path, headers); } /** * 讀取文件 * @param $file 文件路徑(包含文件名) * @param $output_file 可傳遞文件IO數據流(默認爲 null,結果返回文件內容,如設置文件數據流,將返回 true or false) * return 文件內容 或 null */ public byte[] readFile(string path) { Hashtable headers = new Hashtable(); byte[] a = null; HttpWebResponse resp = newWorker("GET", DL + this.bucketname + path, a, headers); StreamReader sr = new StreamReader(resp.GetResponseStream(), Encoding.UTF8); BinaryReader br = new BinaryReader(sr.BaseStream); byte[] by = br.ReadBytes(1024 * 1024 * 100); /// 又拍雲存儲最大文件限制 100Mb,對於普通用戶能夠改寫該值,以減小內存消耗 resp.Close(); return by; } /** * 設置待上傳文件的 Content-MD5 值(如又拍雲服務端收到的文件MD5值與用戶設置的不一致,將回報 406 Not Acceptable 錯誤) * @param $str (文件 MD5 校驗碼) * return null; */ public void setContentMD5(string str) { this.content_md5 = str; } /** * 設置待上傳文件的 訪問密鑰(注意:僅支持圖片空!,設置密鑰後,沒法根據原文件URL直接訪問,需帶 URL 後面加上 (縮略圖間隔標誌符+密鑰) 進行訪問) * 如縮略圖間隔標誌符爲 ! ,密鑰爲 bac,上傳文件路徑爲 /folder/test.jpg ,那麼該圖片的對外訪問地址爲: http://空間域名/folder/test.jpg!bac * @param $str (文件 MD5 校驗碼) * return null; */ public void setFileSecret(string str) { this.file_secret = str; } /** * 獲取文件信息 * @param $file 文件路徑(包含文件名) * return array('type'=> file | folder, 'size'=> file size, 'date'=> unix time) 或 null */ public Hashtable getFileInfo(string file) { Hashtable headers = new Hashtable(); byte[] a = null; HttpWebResponse resp = newWorker("HEAD", DL + this.bucketname + file, a, headers); resp.Close(); Hashtable ht; try { ht = new Hashtable(); ht.Add("type", this.tmp_infos["x-upyun-file-type"]); ht.Add("size", this.tmp_infos["x-upyun-file-size"]); ht.Add("date", this.tmp_infos["x-upyun-file-date"]); } catch (Exception) { ht = new Hashtable(); } return ht; } //獲取上傳後的圖片信息(僅圖片空間有返回數據) public object getWritedFileInfo(string key) { if (this.tmp_infos == new Hashtable()) return ""; return this.tmp_infos[key]; } //計算文件的MD5碼 public static string md5_file(string pathName) { string strResult = ""; string strHashData = ""; byte[] arrbytHashValue; System.IO.FileStream oFileStream = null; System.Security.Cryptography.MD5CryptoServiceProvider oMD5Hasher = new System.Security.Cryptography.MD5CryptoServiceProvider(); try { oFileStream = new System.IO.FileStream(pathName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite); arrbytHashValue = oMD5Hasher.ComputeHash(oFileStream);//計算指定Stream 對象的哈希值 oFileStream.Close(); //由以連字符分隔的十六進制對構成的String,其中每一對錶示value 中對應的元素;例如「F-2C-4A」 strHashData = System.BitConverter.ToString(arrbytHashValue); //替換- strHashData = strHashData.Replace("-", ""); strResult = strHashData; } catch (System.Exception ex) { throw ex; } return strResult.ToLower(); } }
public class FolderItem { public string filename; public string filetype; public int size; public int number; public FolderItem(string filename, string filetype, int size, int number) { this.filename = filename; this.filetype = filetype; this.size = size; this.number = number; } }
class Program { static void Main(string[] args) { UpYun upyun = new UpYun("yangguodemo", "yangguodemo", "abcd5226584"); /// 上傳文件 //Hashtable headers = new Hashtable(); //uy.delete("tes\ttd.jpg", headers); FileStream fs = new FileStream(@"C:\Users\Administrator\Desktop\yangguoDesk\yangguo_error\2.jpg", FileMode.Open, FileAccess.Read); BinaryReader r = new BinaryReader(fs); byte[] postArray = r.ReadBytes((int)fs.Length); Console.WriteLine("上傳文件"); bool b = upyun.writeFile("/2.jpg", postArray, true); // 上傳文件時可以使用 upyun.writeFile("/a/test.jpg",postArray, true); //進行父級目錄的自動建立(最深10級目錄) Console.WriteLine(b); Console.ReadKey(); } }
https://console.upyun.com/#/dashboard/架構
雲存儲的真正代碼:在net目錄下的UploadHandler.cs中dom
#region 上傳雲服務器,並返回雲路勁 //拼接雲路徑 string upyunFileName = CommonHelper.Md5Encode(uploadFileBytes) + Path.GetExtension(uploadFileName); DateTime today = DateTime.Today; string upyunFilePath = "/upload/" + today.Year + "/" + today.Month + "/" + today.Day + "/" + upyunFileName; //上傳雲服務器 try { UpYun upyun = new UpYun("yangguodemo", "yangguodemo", "abcd5226584"); upyun.setContentMD5(CommonHelper.Md5Encode(uploadFileBytes)); //用BitConverter的md5加密出現錯誤,只有ToString("x2")的加密方式沒問題 bool upyunResult = upyun.writeFile(upyunFilePath, uploadFileBytes, true); if (upyunResult) { Result.Url = upyunFilePath; Result.State = UploadState.Success; } else { Result.State = UploadState.FileAccessError; Result.ErrorMessage = "上傳文件失敗:" + uploadFileName; log.Error("上傳文件失敗:" + uploadFileName); } } catch (Exception e) { Result.State = UploadState.FileAccessError; Result.ErrorMessage = e.Message; log.Error("上傳文件異常:" + uploadFileName); } finally { WriteResult(); } #endregion
/// <summary> /// 加密 字節數 /// </summary> /// <param name="bytes">字節數組</param> /// <returns>加密後的字符串</returns> public static string Md5Encode(byte[] bytes) { //MD5 md5 = new MD5CryptoServiceProvider(); //byte[] newBytes = md5.ComputeHash(bytes); //string newStr = BitConverter.ToString(newBytes).Replace("-", ""); //return newStr; MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); bytes = provider.ComputeHash(bytes); StringBuilder sb = new StringBuilder(); foreach(byte b in bytes) { sb.Append(b.ToString("x2").ToLower()); } return sb.ToString(); }
須要UpYun.cs和FolderItem.cs