• 自己手动构建文件服务器


    今天分享一个自己手动搭建文件服务器,本来想上网找个现成的直接用的,结果发现太麻烦,级别太重,不如自己写的快,一天写测,第二天上线使用。

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

    测试上传和下载的功能。

    基本原理说一下

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

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

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

    服务端结构:

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

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

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

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

      1 using FZ.File.Dapper;
      2 using System;
      3 using System.Collections.Generic;
      4 using System.Data;
      5 using System.Linq;
      6 using System.Diagnostics;
      7 using System.IO;
      8 using System.Security.Cryptography;
      9 using System.Text;
     10 
     11 namespace FZ.File.Logic
     12 {
     13     public class FileCoreService
     14     {
     15         /// <summary>
     16         /// 根据文件名和MD5检查是否存在, 检查文件名和MD5都存在 
     17         /// </summary>
     18         /// <param name="filename">文件名</param>
     19         /// <param name="md5str">文件流加密的MD5</param>
     20         /// <returns></returns>
     21         public bool CheckFilNameMD5(string filename, string md5str)
     22         {
     23             using (IDbConnection conn = DBConfig.GetSqlConnection())
     24             {
     25                 try
     26                 {
     27                     string sql = "SELECT COUNT(*) FROM BPM_tb_UploadFile WHERE [FileName]=@FileName AND FileMD5=@FileMD5 ";
     28                     //sql = String.Format(sql,filename,md5str);
     29                     //var count = conn.ExecuteScalar(sql, null, null, null, CommandType.Text);
     30                     var param = new DynamicParameters();
     31                     param.Add("@FileName", filename);
     32                     param.Add("@FileMD5", md5str);
     33                     var count = conn.ExecuteScalar(sql, param, null, 3600, CommandType.Text);
     34                     if ((int)count > 0)
     35                     {
     36                         return true;
     37                     }
     38                 }
     39                 catch (Exception ex)
     40                 {
     41                     throw ex; 
     42                 }
     43             }
     44             return false;
     45         }
     46 
     47         /// <summary>
     48         /// 验证数据的完整性(接收到的文件流MD5与接收到的MD5验证)
     49         /// </summary>
     50         /// <param name="md5str">接收的MD5</param>
     51         /// <param name="sourceStream">文件流</param>
     52         /// <returns></returns>
     53         public bool CheckMD5(string md5str, System.Byte[] sourceStream)
     54         {
     55             var jmd5 = GetMD5HashByByte(sourceStream);
     56             if (md5str == jmd5)
     57             {
     58                 return true;
     59             }
     60             return false;
     61         }
     62         public bool InsertFile(System.Byte[] sourceStream,string md5str,string filename)
     63         {
     64             bool sf = SaveFileToDisk(sourceStream, "D:\UploadFile\", md5str);    //先保存文件
     65             if (sf)
     66             {
     67                 //TO DO 插入数据库
     68                 using (IDbConnection conn = DBConfig.GetSqlConnection())
     69                 {
     70                     try
     71                     {
     72                         string sql = "INSERT INTO BPM_tb_UploadFile([FileName],[FileMD5],[FileSize],[Description]) VALUES('{0}','{1}',{2},'{3}')";
     73                         sql = String.Format(sql, filename, md5str, sourceStream.Length, "");
     74                         var count = conn.Execute(sql, null, null, null, CommandType.Text);
     75                         //var param = new DynamicParameters();
     76                         //param.Add("@FileName", filename);
     77                         //param.Add("@FileMD5", md5str);
     78                         //var count = conn.Execute(sql, param, null, 3600, CommandType.Text);
     79                         if (count > 0)
     80                         {
     81                             return true;
     82                         }
     83                     }
     84                     catch (Exception ex)
     85                     {
     86                         throw ex;
     87                     }
     88                 }
     89             }
     90             return false;        
     91         }
     92         // 根据二进制流生成MD5
     93         private string GetMD5HashByByte(System.Byte[] sourceStream)
     94         {
     95             MD5 md5 = new MD5CryptoServiceProvider();
     96             byte[] result = md5.ComputeHash(sourceStream);
     97             String ret = "";
     98             for (int i = 0; i < result.Length; i++)
     99                 ret += result[i].ToString("x").PadLeft(2, '0');
    100             return ret;
    101         }
    102 
    103         // 根据文件流生成MD5(与上一方法生成结果相同)
    104         private string GetMD5HashByFile(string fileName)
    105         {
    106             FileStream file = new FileStream(fileName, FileMode.Open);
    107             MD5 md5 = new MD5CryptoServiceProvider();
    108             byte[] result = md5.ComputeHash(file);
    109             file.Close();
    110             StringBuilder sb = new StringBuilder();
    111             for (int i = 0; i < result.Length; i++)
    112             {
    113                 sb.Append(result[i].ToString("x2"));
    114             }
    115             return sb.ToString();
    116         }
    117 
    118         // 保存文件流到服务器上指定位置
    119         private bool SaveFileToDisk(System.Byte[] sourceStream, string fileFullName)
    120         {
    121             bool result = false;
    122             try
    123             {
    124                 //待保存的路径
    125                 string savePath = Path.GetDirectoryName(fileFullName);
    126                 if (!Directory.Exists(savePath))
    127                 {
    128                     Directory.CreateDirectory(savePath);
    129                 }
    130 
    131                 using (FileStream fsTarget = new FileStream(fileFullName, FileMode.Create, FileAccess.Write, FileShare.None))
    132                 {
    133                     fsTarget.Write(sourceStream, 0, sourceStream.Length);
    134                     fsTarget.Flush();
    135                     fsTarget.Close();
    136                     result = true;
    137                 }
    138             }
    139             finally
    140             {
    141             }
    142             return result;
    143         }
    144 
    145         private bool SaveFileToDisk(System.Byte[] sourceStream, string filepath,string md5)
    146         {
    147             bool result = false;
    148             string fileFullName = filepath + md5.Substring(0, 2) + "\" + md5.Substring(2, 2)+"\" + md5;
    149             try
    150             {
    151                 //待保存的路径
    152                 string savePath = Path.GetDirectoryName(fileFullName);
    153                 if (!Directory.Exists(savePath))
    154                 {
    155                     Directory.CreateDirectory(savePath);
    156                 }
    157 
    158                 using (FileStream fsTarget = new FileStream(fileFullName, FileMode.Create, FileAccess.Write, FileShare.None))
    159                 {
    160                     fsTarget.Write(sourceStream, 0, sourceStream.Length);
    161                     fsTarget.Flush();
    162                     fsTarget.Close();
    163                     result = true;
    164                 }
    165             }
    166             finally
    167             {
    168             }
    169             return result;
    170         }
    171 
    172         public System.Byte[] ReadFileByte(string filename, string md5str)
    173         {
    174             var filepath = "D:\UploadFile\" + md5str.Substring(0, 2) + "\" + md5str.Substring(2, 2) + "\" + md5str;
    175             FileStream fileStream = new FileStream(filepath, FileMode.Open);
    176             byte[] bytes = new byte[fileStream.Length];
    177             fileStream.Read(bytes, 0, bytes.Length);
    178             fileStream.Close();
    179             return bytes;
    180         }
    181         public FileStream ReadFileStream(string filename, string md5str)
    182         {
    183             var filepath = "D:\UploadFile\" + md5str.Substring(0, 2) + "\" + md5str.Substring(2, 2) + "\" + md5str;
    184             FileStream fileStream = new FileStream(filepath, FileMode.Open);
    185             fileStream.Close();
    186             return fileStream;
    187         }
    188         
    189         
    190     }
    191 }

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

    提供的服务代码

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Services;
     6 using FZ.File.Logic;
     7 using System.IO;
     8 
     9 namespace BPMFileService
    10 {
    11     /// <summary>
    12     /// FileService 的摘要说明
    13     /// </summary>
    14     [WebService(Namespace = "http://tempuri.org/")]
    15     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    16     [System.ComponentModel.ToolboxItem(false)]
    17     // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
    18     // [System.Web.Script.Services.ScriptService]
    19     public class FileService : System.Web.Services.WebService
    20     {
    21 
    22         [WebMethod]
    23         public bool CheckMD5(string filename,string md5str)
    24         {
    25             FileCoreService fs = new FileCoreService();
    26             return fs.CheckFilNameMD5(filename, md5str);
    27         }
    28         [WebMethod]
    29         public bool InsertFile(System.Byte[] FileStream,string filename, string md5str)
    30         {
    31             FileCoreService fs = new FileCoreService();
    32             bool b = fs.CheckMD5(md5str, FileStream);  //验证MD5
    33             if (b)
    34             {
    35                 b = fs.InsertFile(FileStream, md5str,filename); //保存文件,并更新到数据库
    36                 if (b) { LocalLog.Write("插入文件成功,文件名:" + filename + " MD5:" + md5str); } 
    37                 else { LocalLog.Write("插入文件失败,文件名:" + filename + " MD5:" + md5str); }
    38             }
    39             else
    40             {
    41                 LocalLog.Write("接收的文件不完整,请检查!文件名:" + filename + " MD5:" + md5str);
    42             }
    43             return b;
    44         }
    45         [WebMethod]
    46         public Byte[] ReadFile(string filename, string md5str)
    47         {
    48             FileCoreService fs = new FileCoreService();
    49             Byte[] bytes = fs.ReadFileByte(filename, md5str);
    50             LocalLog.Write("读取文件 NAME:" + filename + " MD5:" + md5str);
    51             return bytes;
    52         }
    53     }
    54 }

    客户端上传调用的代码:

     1 protected void btnUp_Click(object sender, EventArgs e)
     2         {
     3             FileServiceSoapClient fsclient = new FileServiceSoapClient();
     4             byte[] fb = FileUpload1.FileBytes;
     5             System.IO.Stream s = FileUpload1.PostedFile.InputStream;
     6             var md5str = GetMD5HashByByte(fb);
     7             var md5str2 = GetMD5HashByFile(s);
     8 
     9             var filename = FileUpload1.FileName;
    10             bool b = fsclient.CheckMD5(filename, md5str);
    11             if (!b)
    12             {                
    13                 if (md5str == md5str2) {
    14                     b = fsclient.InsertFile(fb, filename, md5str);
    15                 }                
    16             }
    17         }

    客户端下载的代码:

    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();
    
            }

     数据库也比较简单:

    日志:

    交流的企鹅群:14615476  ,群员免费提供源码。

  • 相关阅读:
    JavaScript 资源II
    浮动图片(JS)
    2006/1/14的问题以及解答
    Sql问题
    让SQL飞起来
    当页面上的某个控件回发时,保持滚动条位置的。
    自制的日历控件,可以在日历上DIY事情,相关于记一些随笔的文字之类的话题,如“1/28 是新年啊”
    根据的数据库的level关系绑定数据到控件上.
    十大必备VisualStudio插件
    1、12的经验值
  • 原文地址:https://www.cnblogs.com/Elgin/p/10784495.html
Copyright © 2020-2023  润新知