文件上传

写在前面

周末了,在家继续折腾网盘,今天实现网盘文件的上传。

业务逻辑

今天突然发现,用户类中少一个个人网盘的默认大小,这里添加一个字段,记录个人网盘的大小,默认给它1G的空间,在数据库中以字节存储。1G=1073741842字节。所以现在用户信息类现在是这个样子。

/// <summary>
   /// 用户信息类
   /// </summary>
   public class UserInfo
   {
       /// <summary>
       /// 编号
       /// </summary>
       [Key]
       public int Id { set; get; }
       /// <summary>
       /// 用户头像地址
       /// </summary>
       [StringLength(512)]
       [Display(Name = "头像")]
       public string Header { set; get; }
       /// <summary>
       /// 姓名
       /// </summary>
       [MaxLength(64, ErrorMessage = "网名长度不得超过32个字符")]
       [Required(ErrorMessage = "请填写您的名称")]
       [Display(Name = "姓名")]
       public string UserName { set; get; }
       /// <summary>
       /// 密码
       /// </summary>
       [StringLength(32, ErrorMessage = "密码长度不得超多32位")]
       [Required]
       [Display(Name = "密码")]
       public string Pwd { set; get; }
       /// <summary>
       /// 性别
       /// </summary>
       [Display(Name = "性别")]
       public GenderType Gender { set; get; }

       /// <summary>
       /// 所属部门id
       /// </summary>
       [Display(Name = "部门")]
       public Department Department { set; get; }
       /// <summary>
       /// 添加时间
       /// </summary>
       [Display(Name = "创建日期")]
       public DateTime CreateDt { set; get; }
       /// <summary>
       /// 添加时间
       /// </summary>
       [Display(Name = "登录日期")]
       public DateTime LoginDt { set; get; }
       /// <summary>
       /// 登出时间
       /// </summary>
       [Display(Name = "登录日期")]
       public DateTime LoginOutDt { set; get; }
       /// <summary>
       /// 网盘默认大小 1G=1073741842字节
       /// </summary>
       private int _netDiskSize = 1073741842;

       public int NetDiskSize
       {
           get { return _netDiskSize; }
           set { _netDiskSize = value; }
       }


   }

文件信息类MyFile

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wolfy.NetDisk.Model
{
    /// <summary>
    /// 我的文件信息
    /// </summary>
    public class MyFile
    {
        [Key]
        public int Id { set; get; }
        [Display(Name = "文件路径")]
        [StringLength(int.MaxValue)]
        public string FilePath { set; get; }
        [Display(Name = "文件名")]
        [StringLength(1024)]
        public string FileName { set; get; }
        [Display(Name = "文件扩展名")]
        [StringLength(8)]
        public string FileExt { set; get; }
        [Display(Name = "文件图标")]
        [StringLength(32)]
        public string FileIcon { set; get; }
        [Display(Name = "文件大小")]
        public int FileSize { set; get; }
        [Display(Name = "文件MD5")]
        [StringLength(32)]
        public string FileMd5 { set; get; }
        [Display(Name = "文件修改时间")]
        public DateTime ModifyDt { set; get; }
        [Display(Name = "文件上传时间")]
        public DateTime CreateDt { set; get; }
        [Display(Name = "文件是否删除")]
        public bool IsDelete { set; get; }
        [Display(Name = "文件所属")]
        public virtual UserInfo User { set; get; }
    }
}

其他的IDAL,IBLL,BLL,DAL层的代码与userInfo的基本类似,这里不再贴出。

这里使用iframe进行无刷新上传。

<form action="UploadFile" id="fileForm" method="post" enctype="multipart/form-data" target="fileFrame">
    <input type="file" accept="*/*" style="display:none" id="btnFile" name="fileData" />
    <input type="hidden" id="hdFilePath" name="filePath" value="" />
    <input type="hidden" id="hdcallbackInfo" name="name" value="" />
</form>

<iframe style="display:none" name="fileFrame" id="fileFrame"></iframe>

回调js方法

function showMsg(msg, callbackInfo) {
       if (msg) {
           $(".modal-body").html(msg);
           //回调信息
           $("#hdcallbackInfo").val(callbackInfo);
           $("#myModal").modal("show");
       };
   };

服务端

[HttpPost]
public void UploadFile(string filePath)
{
    UserInfo userInfo = Session["user"] as UserInfo;
    if (userInfo == null)
    {
        RedirectToAction("Login", "UserInfo");
    }
    var files = Request.Files;
    if (files.Count > 0)
    {
        var file = files[0];
        string fileName = file.FileName;
        Stream inputStream = file.InputStream;
        string fileSaveFolder = Request.MapPath("~/NetDisk/" + userInfo.UserName);
        if (!string.IsNullOrEmpty(filePath))
        {
            fileSaveFolder = Path.Combine(fileSaveFolder, filePath);
        }

        //如果目标不存在,则创建
        if (!Directory.Exists(fileSaveFolder))
        {
            Directory.CreateDirectory(fileSaveFolder);

        }
        byte[] buffer = new byte[inputStream.Length];
        inputStream.Read(buffer, 0, buffer.Length);
        string strFileMd5 = MD5Helper.GetMD5FromFile(buffer);
        string fileSavePath = Path.Combine(fileSaveFolder, filePath);
        fileSavePath = Path.Combine(fileSaveFolder, fileName);
        //如果文件已经存在
        if (System.IO.File.Exists(fileSavePath))
        {
            //对文件进行重命名
            fileName = ReNameHelper.FileReName(fileSavePath);
            fileSavePath = Path.Combine(fileSaveFolder, fileName);
        }
        file.SaveAs(fileSavePath);
        var currentUser = _userInfoServiceRepository.Find(x => x.Id == userInfo.Id);
        MyFile myFile = new MyFile()
        {
            FileMd5 = strFileMd5,
            ModifyDt = DateTime.Now,
            IsDelete = false,
            FileSize = buffer.Length,
            FilePath = "/NetDisk/" + userInfo.UserName + "/" + fileName,
            FileExt = Path.GetExtension(fileSavePath),
            CreateDt = DateTime.Now,
            FileName = fileName,
            FileIcon = GetFileIcon(Path.GetExtension(fileSavePath)),
            User = currentUser
        };
        //保存数据库
        _myFileServiceRepository.Add(myFile);
        _myFileServiceRepository.SaveChanges();
        string json = new JavaScriptSerializer().Serialize(myFile);
        AlertMsg("上传成功", json);
    }
}
private void AlertMsg(string msg, string fileJson)
{
    Response.ContentType = "text/html";
    Response.Write("<script>parent.showMsg('" + msg + "','" + fileJson + "');</script>");
}
private string GetFileIcon(string fileExt)
{
    string fileIconPath = "/Content/Images/";
    switch (fileExt.ToLower())
    {
        case ".doc":
        case ".docx":
            fileIconPath += "DocType.png";
            break;
        case ".xlx":
        case ".xlxs":
            fileIconPath += "XlsType.png";
            break;
        case ".ppt":
        case ".pptx":
            fileIconPath += "PptType.png";
            break;
        case ".pdf":
            fileIconPath += "PdfType.png";
            break;
        case ".apk":
            fileIconPath += "ApkType.png";
            break;
        case ".dwt":
        case ".dwg":
        case ".dws":
        case ".dxf":
            fileIconPath += "CADType.png";
            break;
        case ".exe":
            fileIconPath += "ExeType.png";
            break;
        case ".png":
        case ".gif":
        case ".jpg":
            fileIconPath += "ImgType.png";
            break;
        case ".txt":
            fileIconPath += "TxtType.png";
            break;
        case ".bt":
            fileIconPath += "TorrentType.png";
            break;
        case ".rmvb":
        case ".avi":
        case ".flv":
            fileIconPath += "VideoType.png";
            break;
        case ".zip":
        case ".7z":
        case ".rar":
            fileIconPath += "MusicType.png";
            break;
        case ".mp3":
            fileIconPath += "MusicType.png";
            break;
        default:
            fileIconPath += "OtherType.png";
            break;
    }
    return fileIconPath;
}

大概逻辑是,在服务端根据用户名创建一个目录,并且判断是否已经存在该文件,如果个人网盘中有该文件了则对其自动重命名,比如1.txt,则重命名后的名称为1(1).txt,文件及文件夹重命名的方法在之前的文章中写了一个工具类,这里直接拿来使用了。

地址:[工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)

测试:

上传成功后,将信息写入隐藏域中,方便其他地方进行使用。

总结

这里使用了iframe的无刷新上传方式,没有使用插件。考虑到有移动端的访问,一般的上传插件是基于flash的,导致兼容性不是很好。