关于HTTP协议的文件服务器

时间:2022-09-13 18:18:13

一般项目都会牵涉到文件的存储。都会单独出一个文件服务器。一般文件服务器常见的分成两种协议上传,一种是ftp,一种是http。一般我们用后者比较多。

做法就是在IIS中配置虚拟目录。然后设置该虚拟目录为可读可写。

文件的上传:

第一步,在web.config中配置文件服务器地址:

  
  
  
< fileserver url ="http://10.20.55.128/FileServer/" blockSize ="1048576"
maxFileSize ="5000000" acceptFileTypes =".txt|.xml|.rar|.xls|.xlsx|.doc|.docx|.gif|.jpg|.bmp" >

 

第二步,编写通用的类来处理上传的逻辑:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Net;
using System.IO;
using System.Threading;
using System.Text;
using System.Diagnostics;
using System.Xml;
using System.Collections;
using Bingosoft.CommonLibrary;

/// <summary>
/// 上传文件
/// </summary>
public static class WebDAVHelper
{
    private static string _targetUrl = ConfigurationManager.AppSettings["CompanyUserPhotoFolder"];
    private static int _blockSize = Int32.Parse(ConfigurationManager.AppSettings["BlockSize"]);

    /// <summary>
    /// 文件服务器URL
    /// </summary>
    public static string TargetUrl
    {
        get
        {
            return _targetUrl;
        }
        set
        {
            _targetUrl = value;
        }
    }

    /// <summary>
    /// 一次写到文件服务器的字节数
    /// </summary>
    public static int BlockSize
    {
        get
        {
            return _blockSize;
        }
        set
        {
            _blockSize = value;
        }
    }

    #region FileUpload

    /// <summary>
    /// 上传文件
    /// </summary>
    /// <param name="fileName">文件路径</param>
    /// <param name="stream">输入文件流</param>
    /// <returns></returns>
    public static string UploadFile(string fileName, Stream stream)
    {
        string url = GetFileUrl(fileName);

        PrepareWebDirectory(url);

        if (WebFileDirectoryExist(url))
        {
            DeleteWebFile(url);
        }

        UploadFileWithoutPrepareDirectory(stream, url);

        return url;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static string GetFileUrl(string fileName)
    {
        int i = fileName.IndexOf(":\\");
        if (i != -1)
            return _targetUrl + "/" + fileName.Substring(i + 2).Replace("\\", "/");
        else
            return _targetUrl + "/" + fileName.Replace("\\", "/");
    }

    /// <summary>
    /// 删除文件/文件夹
    /// </summary>
    /// <param name="fileName">文件路径/文件夹路径</param>
    public static void DeleteFile(string fileName)
    {
        DeleteWebFile(GetFileUrl(fileName));
    }

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="fileName">文件路径</param>
    /// <returns></returns>
    public static HttpWebResponse DownloadFile(string fileName)
    {
        //string url = GetFileUrl(fileName);
        Uri uriTarget = WebDAVHelper.ProcessSpecialCharacters(fileName);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTarget);
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        return response;
    }

    #endregion

    #region WebDAV
    private static void DeleteWebFile(string targetUrl)
    {
        WebDavOperate(targetUrl, "DELETE");
    }

    private static void UploadFileWithoutPrepareDirectory(Stream stream, string targetUrl)
    {
        Uri uri = WebDAVHelper.ProcessSpecialCharacters(targetUrl);
        System.Net.HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.Method = "PUT";
        request.Credentials = System.Net.CredentialCache.DefaultCredentials;
        request.ContentLength = stream.Length;

        byte[] buffer = new byte[_blockSize];

        using (Stream writeStream = request.GetRequestStream())
        {
            using (BinaryReader reader = new BinaryReader(stream))
            {
                int readSizeThisTime;
                readSizeThisTime = reader.Read(buffer, 0, _blockSize);
                while (readSizeThisTime > 0)
                {
                    writeStream.Write(buffer, 0, readSizeThisTime);
                    readSizeThisTime = reader.Read(buffer, 0, _blockSize);

                    Thread.Sleep(0);

                }
            }
        }
        System.GC.Collect();
    }

    private static bool WebFileDirectoryExist(string targetUrl)
    {
        try
        {
            GetDirectoryContents(targetUrl, 0);
        }
        catch (WebException e)
        {
            HttpWebResponse response = (HttpWebResponse)e.Response;
            if (HttpStatusCode.NotFound == response.StatusCode)
            {
                return false;
            }
            else
            {
                throw e;
            }
        }
        return true;
    }

    //**************************************************************
    // GetDirectoryContents()	
    // - Uses HTTP/DAV to get a list of directories
    //**************************************************************

    public static SortedList GetDirectoryContents(string url, int deep)
    {
        //Retrieve the File
        HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(url);
        Request.Headers.Add("Translate: f");
        Request.Credentials = CredentialCache.DefaultCredentials;

        string requestString = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
            "<a:propfind xmlns:a=\"DAV:\">" +
            "<a:prop>" +
            "<a:displayname/>" +
            "<a:iscollection/>" +
            "<a:getlastmodified/>" +
            "</a:prop>" +
            "</a:propfind>";

        Request.Method = "PROPFIND";
        if (-1 == deep)
        {
            Request.Headers.Add("Depth: infinity");
        }
        else
        {
            Request.Headers.Add(string.Format("Depth: {0}", deep));
        }
        Request.ContentLength = requestString.Length;
        Request.ContentType = "text/xml";

        Stream requestStream = Request.GetRequestStream();
        requestStream.Write(Encoding.ASCII.GetBytes(requestString), 0, Encoding.ASCII.GetBytes(requestString).Length);
        requestStream.Close();

        HttpWebResponse Response;
        StreamReader respStream;
        try
        {
            Response = (HttpWebResponse)Request.GetResponse();
            respStream = new StreamReader(Response.GetResponseStream());
        }
        catch (WebException e)
        {
            Debug.WriteLine("APPMANAGER:  Error accessing Url " + url);
            throw e;
        }

        StringBuilder SB = new StringBuilder();

        char[] respChar = new char[1024];
        int BytesRead = 0;

        BytesRead = respStream.Read(respChar, 0, 1024);

        while (BytesRead > 0)
        {
            SB.Append(respChar, 0, BytesRead);
            BytesRead = respStream.Read(respChar, 0, 1024);
        }
        respStream.Close();

        XmlDocument XmlDoc = new XmlDocument();
        XmlDoc.LoadXml(SB.ToString());

        //Create an XmlNamespaceManager for resolving namespaces.
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(XmlDoc.NameTable);
        nsmgr.AddNamespace("a", "DAV:");

        XmlNodeList NameList = XmlDoc.SelectNodes("//a:prop/a:displayname", nsmgr);
        XmlNodeList isFolderList = XmlDoc.SelectNodes("//a:prop/a:iscollection", nsmgr);
        XmlNodeList LastModList = XmlDoc.SelectNodes("//a:prop/a:getlastmodified", nsmgr);
        XmlNodeList HrefList = XmlDoc.SelectNodes("//a:href", nsmgr);

        SortedList ResourceList = new SortedList();
        Resource tempResource;

        for (int i = 0; i < NameList.Count; i++)
        {
            //This check is needed because the PROPFIND request returns the contents of the folder
            //as well as the folder itself.  Exclude the folder.
            if (HrefList[i].InnerText.ToLower().TrimEnd(new char[] { '/' }) != url.ToLower().TrimEnd(new char[] { '/' }))
            {
                tempResource = new Resource();
                tempResource.Name = NameList[i].InnerText;
                tempResource.IsFolder = Convert.ToBoolean(Convert.ToInt32(isFolderList[i].InnerText));
                tempResource.Url = HrefList[i].InnerText;
                tempResource.LastModified = Convert.ToDateTime(LastModList[i].InnerText);
                ResourceList.Add(tempResource.Url, tempResource);
            }
        }

        return ResourceList;
    }

    public static void PrepareWebDirectory(string targetURL)
    {
        //先把Url分拆,放入栈中
        Stack stackUrls = new Stack();

        Uri targetUri = WebDAVHelper.ProcessSpecialCharacters(targetURL);

        string urlHeader = "http://{0}:{1}";
        urlHeader = string.Format(urlHeader, targetUri.Host, targetUri.Port);
        StringBuilder sbUrlBuilder = new StringBuilder(urlHeader);

        foreach (string item in targetUri.Segments)
        {
            sbUrlBuilder.Append(item);
            if (item.EndsWith("/"))   //确认它是一个文件夹而不是一个文件。
            {
                stackUrls.Push(sbUrlBuilder.ToString());
            }
        }

        //从Url栈中弹出元素,检查文件夹是否存在,如果不存在,就放到待建URL栈中
        Stack stackTobeCreate = new Stack();
        string topElement = stackUrls.Pop().ToString();
        while (!WebFileDirectoryExist(topElement))
        {
            stackTobeCreate.Push(topElement);
            if (0 == stackUrls.Count)  //空栈
            {
                throw new Exception("没有找到文件服务器。");
            }
            topElement = stackUrls.Pop().ToString();
        }

        //从待建URL栈中取出待建URL,新建文件夹

        while (0 < stackTobeCreate.Count)
        {
            topElement = stackTobeCreate.Pop().ToString();
            WebDavOperate(topElement, "MKCOL");
        }



    }

    private static void WebDavOperate(string targetURL, string method)
    {
        HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(targetURL);
        Request.Headers.Add("Translate: f");
        Request.Credentials = CredentialCache.DefaultCredentials;


        Request.Method = method;

        HttpWebResponse Response;
        try
        {
            Response = (HttpWebResponse)Request.GetResponse();
        }
        catch (WebException e)
        {
            Debug.WriteLine("APPMANAGER:  Error accessing Url " + targetURL);
            throw e;
        }
    }

    #endregion

    /// <summary>
    /// 当上传或下载的文件名包含有特殊字符"#"时,需要执行以下的函数进行处理
    /// </summary>
    /// <param name="Url"></param>
    /// <returns></returns>
    private static Uri ProcessSpecialCharacters(string Url)
    {
        Uri uriTarget = new Uri(Url);
        if (!Url.Contains("#"))
        {
            return uriTarget;
        }

        UriBuilder msPage = new UriBuilder();
        msPage.Host = uriTarget.Host;
        msPage.Scheme = uriTarget.Scheme;
        msPage.Port = uriTarget.Port;
        msPage.Path = uriTarget.Fragment;
        msPage.Fragment = uriTarget.Fragment;
        Uri uri = msPage.Uri;

        return uri;
    }

}

 

文件的下载:

一般文件的下载通过asp.net的Handle去处理。可以任意定义一种扩展类型交给Handle去处理。在Web.config中作如下配置:

 

  
  
  
< add verb ="*" path ="*.down.ashx" type ="Handler4DownLoadFile" />

Handler4DownLoadFile 是一个后台处理类

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Configuration;
using System.Data;

/// <summary>
/// Summary description for Handler4DownLoadFile
/// </summary>
public class Handler4DownLoadFile : IHttpHandler
{
    public Handler4DownLoadFile()
    {
        //
        // TODO: Add constructor logic here
        //
    }

    public void ProcessRequest(HttpContext context)
    {
        string RelAction = context.Request.QueryString["RelAction"];
        string FileName = context.Request.QueryString["path"];
        string URL = context.Request.QueryString["path"];
        Stream fileStream = null;
        //下载文件权限检验代码Block
        {
            //HasPemission(RelAction)?:
            string ss = "";
        }
        int Size = Convert.ToInt32(ConfigurationManager.AppSettings["ResponseBlockSize"].Trim());
        try
        {
            //if (HttpUtility.UrlPathEncode(FileName).EndsWith("xls", StringComparison.OrdinalIgnoreCase) || HttpUtility.UrlPathEncode(FileName).EndsWith("doc", StringComparison.OrdinalIgnoreCase))
            //{
            //    string fullfilePath = WebDAVHelper.GetFileUrl(FileName);
            //    UpdateBrowseCount(URL);
            //    context.Response.Redirect(fullfilePath);
            //    return;
            //}
            System.Net.HttpWebResponse response = WebDAVHelper.DownloadFile(FileName);
            fileStream = response.GetResponseStream();
            byte[] buffer = new byte[Size];
            context.Response.Clear();
            context.Response.ContentType = response.ContentType;
            FileName = Path.GetFileName(FileName);
            FileName = FileName.Substring(FileName.IndexOf('_') + 1);
            context.Response.AddHeader("Content-Disposition:", "attachment; filename=" + HttpUtility.UrlPathEncode(FileName));
            long toRead = response.ContentLength;//总共需要读的长度
            //long toRead = fileStream.Length;//总共需要读的长度
            int length;//
            while (toRead > 0)
            {
                if (context.Response.IsClientConnected)
                {
                    length = fileStream.Read(buffer, 0, Size);
                    context.Response.OutputStream.Write(buffer, 0, length);
                    context.Response.Flush();
                    toRead = toRead - length;
                }
                else
                {
                    toRead = -1;
                }
            }
            //更新文档的浏览次数
           // UpdateBrowseCount(URL);
        }
        catch (Exception ex)
        {
            throw (new Exception("文件下载出错!"+ex.Message));
            //ClientHelper.ShowMessage(this, "error", "文件下载错误!");
            //ClientHelper.CloseWindow(this, "error", true);
        }
        finally
        {
            if (fileStream != null)
            {
                fileStream.Close();
                fileStream.Dispose();
            }
        }
        System.GC.Collect();
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

    protected void UpdateBrowseCount(string URL)
    {
    
        string sql = string.Format(@"update DocInfo   set  BrowseCount=BrowseCount+1
                    from  DocInfo di  join  FileInfo fi on di.DocID=fi.DocID
                    where fi.URL='{0}'", URL);
        AESDB.Current.ExecuteNonQuery(CommandType.Text, sql);
    }
}