中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

我心中(zhong)的核心組件(jian)(jian)(可插(cha)拔(ba)的AOP)~分布式(shi)文件(jian)(jian)上傳組件(jian)(jian)~基于FastDFS

回到目錄

一些概念

在(zai)大叔框架里總(zong)覺得缺(que)點什么(me),在(zai)最(zui)近的(de)項目(mu)開發中,終(zhong)于知道缺(que)什么(me)了,分(fen)布式文(wen)件存儲組(zu)件,就是(shi)缺(que)它,呵呵,對于分(fen)布式文(wen)件存儲來說,業界比較公認的(de)是(shi)FastDFS組(zu)件,它自己(ji)本身(shen)就是(shi)集群機制,有自己(ji)的(de)路由選擇(ze)和文(wen)件存儲兩個部分(fen),我們(men)通過FastDFS的(de)客戶(hu)端進行上傳后,它會返(fan)回一個在(zai)FastDFS上存儲的(de)路徑,這當(dang)然(ran)是(shi)IO路徑,我們(men)只(zhi)要在(zai)服務(wu)(wu)器上開個Http服務(wu)(wu)器,就可以(yi)以(yi)Http的(de)方法訪問你的(de)文(wen)件了。

我的組件實現方式

前端(duan)上(shang)傳(chuan)控件(表(biao)單方(fang)(fang)式(shi)(shi),swf方(fang)(fang)式(shi)(shi),js方(fang)(fang)法均可(ke))將文件流傳(chuan)給我(wo)們的(de)FastDFS客戶端(duan),通(tong)過客戶端(duan)與(yu)服務端(duan)建立(li)Socket連接,將數據包發(fa)給FastDFS服務端(duan)并等待返(fan)回(hui),上(shang)傳(chuan)成功后返(fan)回(hui)路徑(jing),我(wo)們可(ke)以對路徑(jing)進行HTTP的(de)處理,并存(cun)入(ru)數據庫

fastDFS配合nginx服務器自動生成指定尺寸的圖像

原圖像地址: //www.fastdfs.com/demo/pictruename.jpg

指定尺(chi)寸的圖(tu)像(xiang)地址://www.fastdfs.com/demo/pictruename_100x100.jpg

技術實現

1 一個接口,定義三種上傳規格,普(pu)通(tong)文件(jian)(jian),圖像文件(jian)(jian)和視頻(pin)文件(jian)(jian)(一般需要對(dui)它進行截力)

    public interface IFileUploader
    {
        /// <summary>
        /// 上傳視頻文件
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        VideoUploadResult UploadVideo(VideoUploadParameter param);
        /// <summary>
        /// 上傳普(pu)通文(wen)件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        FileUploadResult UploadFile(FileUploadParameter param);
        /// <summary>
        /// 上(shang)傳圖片
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        /// <remarks>Update:cyr(Ben) 20150317</remarks>
        ImageUploadResult UploadImage(ImageUploadParameter param);
    }

2 一批方法參數,包(bao)括了文件,圖像和視頻等

    /// <summary>
    /// 文件上傳參(can)數基類
    /// </summary>
    public abstract class UploadParameterBase
    {
        public UploadParameterBase()
        {
            MaxSize = 1024 * 1024 * 8;
        }
        /// <summary>
        /// 前一次上傳(chuan)(chuan)時生成的服務器端文件名(ming),如(ru)果(guo)需(xu)要斷點續傳(chuan)(chuan),需(xu)傳(chuan)(chuan)入此文件名(ming)
        /// </summary>
        public string ServiceFileName { get; set; }
        /// <summary>
        /// 文件(jian)流
        /// </summary>
        public Stream Stream { get; set; }
        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName { get; set; }
        /// <summary>
        /// 文件(jian)大小限制(zhi)(單位(wei)bit 默(mo)認1M)
        /// </summary>
        public int MaxSize
        {
            get;
            protected set;
        }
        /// <summary>
        /// 上傳文件類型限制
        /// </summary>
        public string[] FilenameExtension
        {
            get;
            set;
        }

    }
  /// <summary>
    /// 圖(tu)片上傳(chuan)參數對(dui)象(xiang)
    /// </summary>
    public class ImageUploadParameter : UploadParameterBase
    {
        /// <summary>
        /// 構(gou)造(zao)方法
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="fileName"></param>
        /// <param name="filenameExtension">默(mo)認支持(chi)常用圖片格式</param>
        /// <param name="maxSize"></param>
        public ImageUploadParameter(Stream stream, string fileName, string[] filenameExtension = null, int maxSize = 3)
        {
            base.Stream = stream;
            base.FileName = fileName;
            base.MaxSize = maxSize;
            base.FilenameExtension = filenameExtension ?? new string[] { ".jpeg", ".jpg", ".gif", ".png" }; ;

        }
        /// <summary>
        /// 構造方法
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="fileName"></param>
        /// <param name="maxSize">單位為M</param>
        public ImageUploadParameter(Stream stream, string fileName, int maxSize)
            : this(stream, fileName, null, maxSize) { }

    }

3 一批返回類型,包(bao)括對文件,圖像和視頻等方法的返回數據的定義

  /// <summary>
    /// 上(shang)傳文件返(fan)回對象(xiang)基類(lei)
    /// </summary>
    public abstract class UploadResultBase
    {
        /// <summary>
        /// 返回文件地址
        /// </summary>
        public string FilePath { get; set; }
        /// <summary>
        /// 錯誤消息列表
        /// </summary>
        public string ErrorMessage { get; set; }
        /// <summary>
        /// 是否上傳成功
        /// </summary>
        public bool IsValid { get { return string.IsNullOrWhiteSpace(ErrorMessage); } }
    }
  /// <summary>
    /// 視頻(pin)上傳(chuan)返回對象(xiang)
    /// </summary>
    public class VideoUploadResult : UploadResultBase
    {
        /// <summary>
        /// 上(shang)傳(chuan)的視頻截圖地址
        /// </summary>
        public List<string> ScreenshotPaths { get; set; }
        /// <summary> 
        /// 上傳狀(zhuang)態
        /// </summary>
        public UploadStatus UploadStatus { get; set; }

        public VideoUploadResult()
        {
            ScreenshotPaths = new List<string>();
        }
        /// <summary>
        /// 把VideoPath和(he)ScreenshotPaths拼(pin)起(qi)來  以豎線(xian)(|)隔開(kai)
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(FilePath);
            foreach (var item in ScreenshotPaths)
            {
                sb.Append("|" + item);
            }
            return sb.ToString();
        }
    }

4 一個使用FastDFS實現的(de)文(wen)件(jian)上傳實現類(lei)

    /// <summary>
    /// 使(shi)用fastDFS完成(cheng)文件上傳
    /// </summary>
    internal class FastDFSUploader : IFileUploader
    {
        /// <summary>
        /// 目(mu)錄名,需要提前在(zai)fastDFS上建(jian)立
        /// </summary>
        public string DFSGroupName { get { return "tsingda"; } }
        /// <summary>
        /// FastDFS結點
        /// </summary>
        public StorageNode Node { get; private set; }
        /// <summary>
        /// 服務器地址
        /// </summary>
        public string Host { get; private set; }
        /// <summary>
        /// 失敗次數
        /// </summary>
        protected int FaildCount { get; set; }

        public int MaxFaildCount { get; set; }

        public FastDFSUploader()
        {
            InitStorageNode();
            MaxFaildCount = 3;
        }

        #region Private Methods
        private void InitStorageNode()
        {
            Node = FastDFSClient.GetStorageNode(DFSGroupName);
            Host = Node.EndPoint.Address.ToString();
        }

        private List<string> CreateImagePath(string fileName)
        {
            List<string> pathList = new List<string>();
            string snapshotPath = "";
            //視頻截圖
            List<string> localList = new VideoSnapshoter().GetVideoSnapshots(fileName, out snapshotPath);
            foreach (var item in localList)
            {
                string aImage = SmallFileUpload(item);
                pathList.Add(aImage);
            }
            //清除本(ben)地多余的(de)圖(tu)片(pian),有(you)的(de)視頻(pin)截取(qu)的(de)圖(tu)片(pian)多,有(you)的(de)視頻(pin)截取(qu)的(de)圖(tu)片(pian)少
            string[] strArr = Directory.GetFiles(snapshotPath);
            try
            {
                foreach (var strpath in strArr)
                {
                    File.Delete(strpath);
                }
                Directory.Delete(snapshotPath);
            }
            catch (Exception ex)
            {
                Logger.Core.LoggerFactory.Instance.Logger_Info("刪除圖片截圖異常" + ex.Message);
            }
            return pathList;
        }
        private string SmallFileUpload(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
                throw new ArgumentNullException("filePath 參數不(bu)能(neng)為(wei)空(kong)");
            if (!File.Exists(filePath))
                throw new Exception("上傳的文(wen)件不存在(zai)");
            byte[] content;
            using (FileStream streamUpload = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                using (BinaryReader reader = new BinaryReader(streamUpload))
                {
                    content = reader.ReadBytes((int)streamUpload.Length);
                }
            }
            string shortName = FastDFSClient.UploadFile(Node, content, "png");
            return GetFormatUrl(shortName);
        }
        /// <summary>
        /// 文(wen)件分塊(kuai)上傳,適合大(da)文(wen)件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private string MultipartUpload(UploadParameterBase param)
        {
            Stream stream = param.Stream;
            if (stream == null)
                throw new ArgumentNullException("stream參數(shu)不能為空(kong)");
            int size = 1024 * 1024;
            byte[] content = new byte[size];
            Stream streamUpload = stream;
            //  第(di)一個數據包上傳或獲取已上傳的位置(zhi)
            string ext = param.FileName.Substring(param.FileName.LastIndexOf('.') + 1);
            streamUpload.Read(content, 0, size);
            string shortName = FastDFSClient.UploadAppenderFile(Node, content, ext);

            BeginUploadPart(stream, shortName);

            return CompleteUpload(stream, shortName);
        }
        /// <summary>
        /// 斷點續傳
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="serverShortName"></param>
        private void ContinueUploadPart(Stream stream, string serverShortName)
        {
            var serviceFile = FastDFSClient.GetFileInfo(Node, serverShortName);
            stream.Seek(serviceFile.FileSize, SeekOrigin.Begin);
            BeginUploadPart(stream, serverShortName);
        }
        /// <summary>
        /// 從指定位置開始上傳文(wen)件
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="beginOffset"></param>
        /// <param name="serverShortName"></param>
        private void BeginUploadPart(Stream stream, string serverShortName)
        {
            try
            {
                int size = 1024 * 1024;
                byte[] content = new byte[size];

                while (stream.Position < stream.Length)
                {
                    stream.Read(content, 0, size);

                    var result = FastDFSClient.AppendFile(DFSGroupName, serverShortName, content);
                    if (result.Length == 0)
                    {
                        FaildCount = 0;
                        continue;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Core.LoggerFactory.Instance.Logger_Info("上傳文件中斷!" + ex.Message);
                if (NetCheck())
                {
                    //重試(shi)
                    if (FaildCount < MaxFaildCount)
                    {
                        FaildCount++;
                        InitStorageNode();
                        ContinueUploadPart(stream, serverShortName);
                    }
                    else
                    {
                        Logger.Core.LoggerFactory.Instance.Logger_Info("已達到失敗重試次數仍沒有(you)上傳成功"); ;
                        throw ex;
                    }
                }
                else
                {
                    Logger.Core.LoggerFactory.Instance.Logger_Info("當前網(wang)絡不可用(yong)");
                    throw ex;
                }
            }
        }
        /// <summary>
        /// 網絡可用為True,否則為False
        /// </summary>
        /// <returns></returns>
        private bool NetCheck()
        {
            return NetworkInterface.GetIsNetworkAvailable();
        }
        /// <summary>
        /// 拼接Url
        /// </summary>
        /// <param name="shortName"></param>
        /// <returns></returns>
        private string GetFormatUrl(string shortName)
        {
            return string.Format("//{0}/{1}/{2}", Host, DFSGroupName, shortName);
        }

        private string CompleteUpload(Stream stream, string shortName)
        {
            stream.Close();
            return GetFormatUrl(shortName);
        }

        private string GetShortNameFromUrl(string url)
        {
            if (string.IsNullOrEmpty(url))
                return string.Empty;
            Uri uri = new Uri(url);
            string urlFirstPart = string.Format("//{0}/{1}/", Host, DFSGroupName);
            if (!url.StartsWith(urlFirstPart))
                return string.Empty;
            return url.Substring(urlFirstPart.Length);
        }
        #endregion

        #region IFileUploader 成員

        /// <summary>
        /// 上傳視頻
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public VideoUploadResult UploadVideo(VideoUploadParameter param)
        {
            VideoUploadResult result = new VideoUploadResult();
            string fileName = MultipartUpload(param);
            if (param.IsScreenshot)
            {
                result.ScreenshotPaths = CreateImagePath(fileName);
            }
            result.FilePath = fileName;
            return result;
        }

        /// <summary>
        /// 上傳(chuan)普通文(wen)件
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public FileUploadResult UploadFile(FileUploadParameter param)
        {
            var result = new FileUploadResult();
            try
            {
                string fileName = MultipartUpload(param);
                result.FilePath = fileName;
            }
            catch (Exception ex)
            {

                result.ErrorMessage = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 上傳(chuan)圖片
        /// </summary>
        /// <param name="param"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public ImageUploadResult UploadImage(ImageUploadParameter param)
        {
            byte[] content;
            string shortName = "";
            string ext = System.IO.Path.GetExtension(param.FileName).ToLower();
            if (param.FilenameExtension != null && param.FilenameExtension.Contains(ext))
            {
                if (param.Stream.Length > param.MaxSize)
                {
                    return new ImageUploadResult
                    {
                        ErrorMessage = "圖片大小(xiao)超(chao)過指(zhi)定大小(xiao)" + param.MaxSize / 1048576 + "M,請重新(xin)選擇(ze)",
                        FilePath = shortName
                    };
                }
                else
                {
                    using (BinaryReader reader = new BinaryReader(param.Stream))
                    {
                        content = reader.ReadBytes((int)param.Stream.Length);
                    }

                    shortName = FastDFSClient.UploadFile(Node, content, ext.Contains('.') ? ext.Substring(1) : ext);
                }
            }
            else
            {
                return new ImageUploadResult
                {
                    ErrorMessage = "文件類型(xing)不匹(pi)配(pei)",
                    FilePath = shortName
                };

            }
            return new ImageUploadResult
            {
                FilePath = CompleteUpload(param.Stream, shortName),
            };
        }
        #endregion
    }

5 一個文(wen)件上傳(chuan)的生產者,經典(dian)的單例(li)模式(shi)的體現

 /// <summary>
    /// 文件上傳生產者
    /// </summary>
    public class FileUploaderFactory
    {
        /// <summary>
        /// 上傳實(shi)例(li)
        /// </summary>
        public readonly static IFileUploader Instance;
        private static object lockObj = new object();
        static FileUploaderFactory()
        {
            if (Instance == null)
            {
                lock (lockObj)
                {
                    Instance = new FastDFSUploader();
                }
            }
        }
    }

6 前臺的(de)文件上傳(chuan)控件,你(ni)可以(yi)隨便選(xuan)擇了,它與前臺是(shi)解耦的(de),沒有什(shen)么關系,用哪種方法實現(xian)都可以(yi),呵呵

     [HttpPost]
        public ActionResult Index(FormCollection form)
        {
            var file = Request.Files[0];
            var result = Project.FileUpload.FileUploaderFactory.Instance.UploadFile(new Project.FileUpload.Parameters.FileUploadParameter
            {
                FileName = file.FileName,
                Stream = file.InputStream,
            });
            ViewBag.Path = result.FilePath;
            return View();
        }

最后(hou)我們看一(yi)下我的Project.FileUpload的完(wan)整結構

它隸屬于大叔的Project.Frameworks集合,我們在這里,對Project.FileUpload說一聲:Hello FileUpload,We wait for you for a long time...

 回到目錄

posted @ 2015-08-19 15:06  張占嶺  閱讀(2270)  評論(3)    收藏  舉報