• 技术文章 >后端开发 >C#.Net教程

    C# 快速手动构建文件服务器

    little bottlelittle bottle2019-04-30 12:05:05转载3188
    今天分享一篇关于自己手动搭建文件服务器的文章,非常方便,想拥有属于自己的文件服务器的朋友可以学习一下。

    如下图,下面是调用的一个测试使用的界面。

    测试上传和下载的功能。

    相关教程:C#视频教程

    基本原理说一下

    1.客户端上传file,转换成二进制流到服务器,服务器接收进行MD5加密,把文件及密码存入文件服务器库,文件根据MD5保存进本地文件夹,文件夹命名第一级取MD5前二位,第二级文件目录是MD5第3和4位,保存的文件重新命名,名称是当前加密的MD5。 当然,加密储存需要验证的,如果本地已经存了这个MD5就认为已经保存了相同的文件,就不需要再保存。

    2.下载文件的时候 直接通过该MD5取文件即可。

    上图是基本流程,逻辑上还是有漏洞,实际上又有改动。基本流程是这样了,可以大概看看,懒得再划一个图了。

    服务端结构:

    FileService.asmx 提供服务,核心代码在FileCoreService.cs. 本项目用的Dapper,简单方便、实用。

    WebApplication1 就是测试用的,客户端调用的了。

    WFBPMFile 可以忽略了,我的一个转换功能,原先文件是文件流存入数据库里的,大概100G,然后转换成文件,放入文件服务器了。

    核心代码 放出来吧,喜欢的可以拿去.


    using FZ.File.Dapper;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Diagnostics;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace FZ.File.Logic
    {
        public class FileCoreService
        {
            /// <summary>
            /// 根据文件名和MD5检查是否存在, 检查文件名和MD5都存在 
            /// </summary>
            /// <param name="filename">文件名</param>
            /// <param name="md5str">文件流加密的MD5</param>
            /// <returns></returns>
            public bool CheckFilNameMD5(string filename, string md5str)
            {
                using (IDbConnection conn = DBConfig.GetSqlConnection())
                {
                    try
                    {
                        string sql = "SELECT COUNT(*) FROM BPM_tb_UploadFile WHERE [FileName]=@FileName AND FileMD5=@FileMD5 ";
                        //sql = String.Format(sql,filename,md5str);
                        //var count = conn.ExecuteScalar(sql, null, null, null, CommandType.Text);
                        var param = new DynamicParameters();
                        param.Add("@FileName", filename);
                        param.Add("@FileMD5", md5str);
                        var count = conn.ExecuteScalar(sql, param, null, 3600, CommandType.Text);
                        if ((int)count > 0)
                        {
                            return true;
                        }
                    }
                    catch (Exception ex)
                    {
                        throw ex; 
                    }
                }
                return false;
            }
    
            /// <summary>
            /// 验证数据的完整性(接收到的文件流MD5与接收到的MD5验证)
            /// </summary>
            /// <param name="md5str">接收的MD5</param>
            /// <param name="sourceStream">文件流</param>
            /// <returns></returns>
            public bool CheckMD5(string md5str, System.Byte[] sourceStream)
            {
                var jmd5 = GetMD5HashByByte(sourceStream);
                if (md5str == jmd5)
                {
                    return true;
                }
                return false;
            }
            public bool InsertFile(System.Byte[] sourceStream,string md5str,string filename)
            {
                bool sf = SaveFileToDisk(sourceStream, "D:\\UploadFile\\", md5str);    //先保存文件
                if (sf)
                {
                    //TO DO 插入数据库
                    using (IDbConnection conn = DBConfig.GetSqlConnection())
                    {
                        try
                        {
                            string sql = "INSERT INTO BPM_tb_UploadFile([FileName],[FileMD5],[FileSize],[Description]) VALUES('{0}','{1}',{2},'{3}')";
                            sql = String.Format(sql, filename, md5str, sourceStream.Length, "");
                            var count = conn.Execute(sql, null, null, null, CommandType.Text);
                            //var param = new DynamicParameters();
                            //param.Add("@FileName", filename);
                            //param.Add("@FileMD5", md5str);
                            //var count = conn.Execute(sql, param, null, 3600, CommandType.Text);
                            if (count > 0)
                            {
                                return true;
                            }
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
                }
                return false;        
            }
            // 根据二进制流生成MD5
            private string GetMD5HashByByte(System.Byte[] sourceStream)
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] result = md5.ComputeHash(sourceStream);
                String ret = "";
                for (int i = 0; i < result.Length; i++)
                    ret += result[i].ToString("x").PadLeft(2, '0');
                return ret;
            }
    
            // 根据文件流生成MD5(与上一方法生成结果相同)
            private string GetMD5HashByFile(string fileName)
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] result = md5.ComputeHash(file);
                file.Close();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < result.Length; i++)
                {
                    sb.Append(result[i].ToString("x2"));
                }
                return sb.ToString();
            }
    
            // 保存文件流到服务器上指定位置
            private bool SaveFileToDisk(System.Byte[] sourceStream, string fileFullName)
            {
                bool result = false;
                try
                {
                    //待保存的路径
                    string savePath = Path.GetDirectoryName(fileFullName);
                    if (!Directory.Exists(savePath))
                    {
                        Directory.CreateDirectory(savePath);
                    }
    
                    using (FileStream fsTarget = new FileStream(fileFullName, FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        fsTarget.Write(sourceStream, 0, sourceStream.Length);
                        fsTarget.Flush();
                        fsTarget.Close();
                        result = true;
                    }
                }
                finally
                {
                }
                return result;
            }
    
            private bool SaveFileToDisk(System.Byte[] sourceStream, string filepath,string md5)
            {
                bool result = false;
                string fileFullName = filepath + md5.Substring(0, 2) + "\\" + md5.Substring(2, 2)+"\\" + md5;
                try
                {
                    //待保存的路径
                    string savePath = Path.GetDirectoryName(fileFullName);
                    if (!Directory.Exists(savePath))
                    {
                        Directory.CreateDirectory(savePath);
                    }
    
                    using (FileStream fsTarget = new FileStream(fileFullName, FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        fsTarget.Write(sourceStream, 0, sourceStream.Length);
                        fsTarget.Flush();
                        fsTarget.Close();
                        result = true;
                    }
                }
                finally
                {
                }
                return result;
            }
    
            public System.Byte[] ReadFileByte(string filename, string md5str)
            {
                var filepath = "D:\\UploadFile\\" + md5str.Substring(0, 2) + "\\" + md5str.Substring(2, 2) + "\\" + md5str;
                FileStream fileStream = new FileStream(filepath, FileMode.Open);
                byte[] bytes = new byte[fileStream.Length];
                fileStream.Read(bytes, 0, bytes.Length);
                fileStream.Close();
                return bytes;
            }
            public FileStream ReadFileStream(string filename, string md5str)
            {
                var filepath = "D:\\UploadFile\\" + md5str.Substring(0, 2) + "\\" + md5str.Substring(2, 2) + "\\" + md5str;
                FileStream fileStream = new FileStream(filepath, FileMode.Open);
                fileStream.Close();
                return fileStream;
            }
            
            
        }
    }

    上面保存的文件路径自己写入配置文件吧,还有日志文件路径,自己到配置文件改一下。代码写的很烂,各位高人忽略即可。

    提供的服务代码


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using FZ.File.Logic;
    using System.IO;
    
    namespace BPMFileService
    {
        /// <summary>
        /// FileService 的摘要说明
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
        // [System.Web.Script.Services.ScriptService]
        public class FileService : System.Web.Services.WebService
        {
    
            [WebMethod]
            public bool CheckMD5(string filename,string md5str)
            {
                FileCoreService fs = new FileCoreService();
                return fs.CheckFilNameMD5(filename, md5str);
            }
            [WebMethod]
            public bool InsertFile(System.Byte[] FileStream,string filename, string md5str)
            {
                FileCoreService fs = new FileCoreService();
                bool b = fs.CheckMD5(md5str, FileStream);  //验证MD5
                if (b)
                {
                    b = fs.InsertFile(FileStream, md5str,filename); //保存文件,并更新到数据库
                    if (b) { LocalLog.Write("插入文件成功,文件名:" + filename + " MD5:" + md5str); } 
                    else { LocalLog.Write("插入文件失败,文件名:" + filename + " MD5:" + md5str); }
                }
                else
                {
                    LocalLog.Write("接收的文件不完整,请检查!文件名:" + filename + " MD5:" + md5str);
                }
                return b;
            }
            [WebMethod]
            public Byte[] ReadFile(string filename, string md5str)
            {
                FileCoreService fs = new FileCoreService();
                Byte[] bytes = fs.ReadFileByte(filename, md5str);
                LocalLog.Write("读取文件 NAME:" + filename + " MD5:" + md5str);
                return bytes;
            }
        }
    }

    客户端上传调用的代码:


    protected void btnUp_Click(object sender, EventArgs e)
            {
                FileServiceSoapClient fsclient = new FileServiceSoapClient();
                byte[] fb = FileUpload1.FileBytes;
                System.IO.Stream s = FileUpload1.PostedFile.InputStream;
                var md5str = GetMD5HashByByte(fb);
                var md5str2 = GetMD5HashByFile(s);
    
                var filename = FileUpload1.FileName;
                bool b = fsclient.CheckMD5(filename, md5str);
                if (!b)
                {                
                    if (md5str == md5str2) {
                        b = fsclient.InsertFile(fb, filename, md5str);
                    }                
                }
            }

    客户端下载的代码:


    protected void btndown_Click(object sender, EventArgs e)
            {
                FileServiceSoapClient fsclinent = new FileServiceSoapClient();
                var Dbytes = fsclinent.ReadFile("新建文本文档.txt", "450ccb8dc556e010ff95b787084d2c51");
                //byte[] bytes =byte.Parse(Dbytes.ToString()):
                Response.ContentType = "application/octet-stream;charset=gb2321";
                //通知浏览器下载文件而不是打开;对中文名称进行编码
                Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode("新建文本文档.txt", System.Text.Encoding.UTF8));
                Response.BinaryWrite(Dbytes);
                Response.Flush();
                Response.End();
    
            }

    数据库也比较简单:

    日志:

    以上就是C# 快速手动构建文件服务器的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:博客园,如有侵犯,请联系admin@php.cn删除
    专题推荐:C# 文件服务器
    上一篇:c语言 三种求回文数的算法 下一篇:c语言数组怎么定义?
    千万级数据并发解决方案

    相关文章推荐

    • Linux下文件服务器配置 无盘服务器配置 数据库服务器配置 服务器配置参• Windows下无法使用Nginx作为一个http文件服务器(权限问题?)• C#用来做什么的• c#中反射是什么?
    1/1

    PHP中文网