搜索
首页后端开发C#.Net教程C# 快速手动构建文件服务器

今天分享一篇关于自己手动搭建文件服务器的文章,非常方便,想拥有属于自己的文件服务器的朋友可以学习一下。

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

测试上传和下载的功能。

相关教程: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(&#39;{0}&#39;,&#39;{1}&#39;,{2},&#39;{3}&#39;)";
                        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, &#39;0&#39;);
            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#.net适合您吗?评估其适用性c#.net适合您吗?评估其适用性Apr 13, 2025 am 12:03 AM

c#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

.NET中的C#代码:探索编程过程.NET中的C#代码:探索编程过程Apr 12, 2025 am 12:02 AM

C#在.NET中的编程过程包括以下步骤:1)编写C#代码,2)编译为中间语言(IL),3)由.NET运行时(CLR)执行。C#在.NET中的优势在于其现代化语法、强大的类型系统和与.NET框架的紧密集成,适用于从桌面应用到Web服务的各种开发场景。

C#.NET:探索核心概念和编程基础知识C#.NET:探索核心概念和编程基础知识Apr 10, 2025 am 09:32 AM

C#是一种现代、面向对象的编程语言,由微软开发并作为.NET框架的一部分。1.C#支持面向对象编程(OOP),包括封装、继承和多态。2.C#中的异步编程通过async和await关键字实现,提高应用的响应性。3.使用LINQ可以简洁地处理数据集合。4.常见错误包括空引用异常和索引超出范围异常,调试技巧包括使用调试器和异常处理。5.性能优化包括使用StringBuilder和避免不必要的装箱和拆箱。

测试C#.NET应用程序:单元,集成和端到端测试测试C#.NET应用程序:单元,集成和端到端测试Apr 09, 2025 am 12:04 AM

C#.NET应用的测试策略包括单元测试、集成测试和端到端测试。1.单元测试确保代码的最小单元独立工作,使用MSTest、NUnit或xUnit框架。2.集成测试验证多个单元组合的功能,常用模拟数据和外部服务。3.端到端测试模拟用户完整操作流程,通常使用Selenium进行自动化测试。

高级C#.NET教程:ACE您的下一次高级开发人员面试高级C#.NET教程:ACE您的下一次高级开发人员面试Apr 08, 2025 am 12:06 AM

C#高级开发者面试需要掌握异步编程、LINQ、.NET框架内部工作原理等核心知识。1.异步编程通过async和await简化操作,提升应用响应性。2.LINQ以SQL风格操作数据,需注意性能。3..NET框架的CLR管理内存,垃圾回收需谨慎使用。

C#.NET面试问题和答案:提高您的专业知识C#.NET面试问题和答案:提高您的专业知识Apr 07, 2025 am 12:01 AM

C#.NET面试问题和答案包括基础知识、核心概念和高级用法。1)基础知识:C#是微软开发的面向对象语言,主要用于.NET框架。2)核心概念:委托和事件允许动态绑定方法,LINQ提供强大查询功能。3)高级用法:异步编程提高响应性,表达式树用于动态代码构建。

使用C#.NET建筑微服务:建筑师实用指南使用C#.NET建筑微服务:建筑师实用指南Apr 06, 2025 am 12:08 AM

C#.NET是构建微服务的热门选择,因为其生态系统强大且支持丰富。1)使用ASP.NETCore创建RESTfulAPI,处理订单创建和查询。2)利用gRPC实现微服务间的高效通信,定义和实现订单服务。3)通过Docker容器化微服务,简化部署和管理。

C#.NET安全性最佳实践:防止常见漏洞C#.NET安全性最佳实践:防止常见漏洞Apr 05, 2025 am 12:01 AM

C#和.NET的安全最佳实践包括输入验证、输出编码、异常处理、以及身份验证和授权。1)使用正则表达式或内置方法验证输入,防止恶意数据进入系统。2)输出编码防止XSS攻击,使用HttpUtility.HtmlEncode方法。3)异常处理避免信息泄露,记录错误但不返回详细信息给用户。4)使用ASP.NETIdentity和Claims-based授权保护应用免受未授权访问。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具