整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          asp.net實現圖片在線上傳并在線裁剪

          asp.net實現圖片在線上傳并在線裁剪

          、說明

            接上一篇文章uploadify實現多附件上傳完成后,又突然用到頭像上傳并在線裁剪。在網上找個眾多例子都沒有符合要求的,有一篇文章寫的不錯,就是文旺老兄寫的這篇Asp.Net平臺下的圖片在線裁剪功能的實現,大家可以看一下,寫的真不錯。我就是在參考了他的代碼下,結合uploadify使用一般處理程序實現了這個功能,寫下了這篇在asp.net實現圖片在線上傳并在線裁剪,有點繞口哈,廢話不多說,現奉上代碼,供同學們交流參考,有什么不對的地方,望請大家多多提提建議,多謝!多謝!

          2、組成

            首先說明一下代碼實現所用到的技術,僅供參考:

              開發工具:vs2010

              目標框架:.NET Framework3.5

              jcrop:Jcrop.js v0.9.12

              Uploadify:uploadify-v3.1

              Jquery:jquery-1.9.0.js

            最后我會將整個Demo上傳,如果同學們的電腦上有開發環境可直接打開項目解決方案運行。

          3、代碼

            Default.aspx(測試頁面)



          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          61

          62

          63

          64

          65

          66

          67

          68

          69

          70

          71

          72

          73

          74

          75

          76

          77

          78

          79

          80

          81

          82

          83

          84

          85

          86

          87

          88

          89

          90

          91

          92

          93

          94

          95

          96

          97

          98

          99

          100

          101

          102

          103

          104

          105

          <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ImgJcrop._Default" %>

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

          <html xmlns="http://www.w3.org/1999/xhtml">

          <head runat="server">

          <title>在線裁剪</title>

          <link href="Scripts/jcrop/jquery.Jcrop.css" rel="stylesheet" type="text/css" />

          <link href="Scripts/uploadify-v3.1/uploadify.css" rel="stylesheet" type="text/css" />

          <script src="Scripts/jquery.1.9.0.min.js" type="text/javascript"></script>

          <script src="Scripts/jcrop/jquery.Jcrop.js" type="text/javascript"></script>

          <script src="Scripts/uploadify-v3.1/jquery.uploadify-3.1.js" type="text/javascript"></script>

          <script type="text/javascript">

          $(function () {

          var jcrop_api, boundx, boundy;

          $("#file_upload").uploadify({

          "auto": true,

          "buttonText": "選擇圖片",

          "swf": "Scripts/uploadify-v3.1/uploadify.swf",

          "uploader": "App_Handler/Uploadify.ashx?action=upload",

          "fileTypeExts": "*.jpg; *.jpeg; *.gif; *.png; *.bmp",

          "fileTypeDesc": "支持的格式:",

          "multi": false,

          "removeCompleted": false,

          "onUploadStart": function (file) {

          $("#file_upload-queue").hide();

          },

          "onUploadSuccess": function (file, data, response) {

          var row=eval("[" + data + "]");

          if (row[0]["status"]==0) {

          $("#cutimg").html("<img id=\"imgOriginal\" name=\"imgOriginal\" /><div style=\"overflow: hidden; margin-top: 20px;\"><div style=\"width: 120px; height: 120px; overflow: hidden;\"><img id=\"imgPreview\" /></div><br /><input type=\"button\" id=\"btnImgCut\" onclick=\"cutSaveImg()\" value=\"裁剪并保存圖片\" /></div>");

          $("#cutimg img").each(function () { $(this).attr("src", row[0]["message"]); });

          $("#hidImgUrl").val(row[0]["message"]);

          $('#imgOriginal').Jcrop({

          onChange: updatePreview,

          onSelect: updatePreview,

          aspectRatio: 1,

          //maxSize: [120, 120],

          setSelect: [0, 0, 120, 120]

          }, function () {

          var bounds=this.getBounds();

          boundx=bounds[0];

          boundy=bounds[1];

          jcrop_api=this;

          });

          } else {

          alert(row[0]["message"]);

          }

          }

          });

          function updatePreview(c) {

          if (parseInt(c.w) > 0) {

          var rx=120 / c.w;

          var ry=120 / c.h;

          $("#imgPreview").css({

          width: Math.round(rx * boundx) + "px",

          height: Math.round(ry * boundy) + "px",

          marginLeft: "-" + Math.round(rx * c.x) + "px",

          marginTop: "-" + Math.round(ry * c.y) + "px"

          });

          }

          $("#hidXone").val(c.x);

          $("#hidYone").val(c.y);

          $("#hidXtwo").val(c.hidXtwo);

          $("#hidYtwo").val(c.hidYtwo);

          $("#hidImgWidth").val(c.w);

          $("#hidImgHeight").val(c.h);

          };

          });

          function cutSaveImg() {

          $.ajax({

          type: "post",

          url: "App_Handler/Uploadify.ashx?action=cutsaveimg",

          data: { strImgUrl: $("#imgOriginal")[0].src, hidXone: $("#hidXone").val(), hidYone: $("#hidYone").val(), hidImgWidth: $("#hidImgWidth").val(), hidImgHeight: $("#hidImgHeight").val() },

          dataType: "html",

          success: function (data) {

          var row=eval("[" + data + "]");

          if (row[0]["status"]==0) { }

          alert(row[0]["message"]);

          }

          });

          }

          </script>

          </head>

          <body>

          <form id="form1" runat="server">

          <div>

          <input type="file" id="file_upload" name="file_upload" />

          </div>

          <div id="cutimg">

          </div>

          <asp:HiddenField ID="hidXone" runat="server" />

          <asp:HiddenField ID="hidYone" runat="server" />

          <asp:HiddenField ID="hidXtwo" runat="server" />

          <asp:HiddenField ID="hidYtwo" runat="server" />

          <asp:HiddenField ID="hidImgWidth" runat="server" />

          <asp:HiddenField ID="hidImgHeight" runat="server" />

          <asp:HiddenField ID="hidImgUrl" runat="server" />

          </form>

          </body>

          </html>



          Uploadify.ashx(一般處理程序)



          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          61

          62

          63

          64

          65

          66

          67

          68

          69

          70

          71

          72

          73

          74

          75

          76

          77

          78

          79

          80

          81

          82

          83

          84

          85

          86

          87

          88

          89

          90

          91

          92

          93

          94

          95

          96

          97

          98

          99

          100

          101

          102

          103

          104

          105

          106

          107

          108

          109

          110

          111

          112

          113

          114

          115

          116

          117

          118

          119

          120

          121

          122

          123

          124

          125

          126

          127

          128

          129

          130

          131

          132

          133

          134

          135

          136

          137

          138

          139

          140

          141

          142

          143

          144

          145

          146

          147

          148

          149

          150

          151

          152

          153

          154

          155

          156

          157

          158

          159

          160

          161

          162

          163

          164

          165

          166

          167

          168

          169

          170

          171

          172

          173

          174

          175

          176

          177

          178

          179

          180

          181

          182

          183

          184

          185

          186

          187

          188

          189

          190

          191

          192

          193

          194

          195

          196

          197

          198

          199

          <%@ WebHandler Language="C#" Class="UploadifyUpload" %>

          using System;

          using System.Collections;

          using System.Data;

          using System.Web;

          using System.Linq;

          using System.Web.Services;

          using System.Web.Services.Protocols;

          using System.Web.SessionState;

          using System.IO;

          using System.Collections.Generic;

          using System.Web.UI.WebControls;

          using System.Text;

          using System.Drawing;

          using System.Drawing.Imaging;

          public class UploadifyUpload : IHttpHandler, IRequiresSessionState

          {

          public void ProcessRequest(HttpContext context)

          {

          context.Response.ContentType="text/plain";

          context.Response.Charset="utf-8";

          string action=context.Request["action"];

          switch (action)

          {

          case "upload":

          //上傳圖片

          upload(context);

          break;

          case "cutsaveimg":

          //裁剪并保存

          cutsaveimg(context);

          break;

          }

          context.Response.End();

          }

          /// <summary>

          /// 上傳圖片

          /// </summary>

          /// <param name="context"></param>

          private void upload(HttpContext context)

          {

          HttpPostedFile postedFile=context.Request.Files["Filedata"];

          if (postedFile !=null)

          {

          string fileName, fileExtension;

          int fileSize;

          fileName=postedFile.FileName;

          fileSize=postedFile.ContentLength;

          if (fileName !="")

          {

          fileExtension=postedFile.FileName.Substring(postedFile.FileName.LastIndexOf('.'));

          string strPath=context.Server.MapPath("/") + "\App_File\Upload\";//設置文件的路徑

          string strFileName="upload" + DateTime.Now.ToString("yyyyMMddHHmmss") + fileExtension;

          string strFileUrl=strPath + strFileName;//保存文件路徑

          if (!Directory.Exists(strPath))

          {

          Directory.CreateDirectory(strPath);

          }

          postedFile.SaveAs(strFileUrl);//先保存源文件

          context.Response.Write("{\"status\":0,\"message\":\"/App_File/Upload/" + strFileName + "\"}");

          }

          else

          {

          context.Response.Write("{\"status\":1,\"message\":\"上傳失敗!\"}");

          }

          }

          else

          {

          context.Response.Write("{\"status\":1,\"message\":\"上傳失敗!\"}");

          }

          }

          /// <summary>

          /// 裁剪并保存圖片

          /// </summary>

          /// <param name="context"></param>

          private void cutsaveimg(HttpContext context)

          {

          string strImgUrl=context.Request["strImgUrl"];

          string strXone=context.Request["hidXone"];

          string strYone=context.Request["hidYone"];

          string strImgWidth=context.Request["hidImgWidth"];

          string strImgHeight=context.Request["hidImgHeight"];

          string[] urls=strImgUrl.Split('/');

          string str_url=urls.Last();

          try

          {

          string strOldFiel=context.Server.MapPath("~/App_File/Upload/");

          string strNewFiel=context.Server.MapPath("~/App_File/Cut/");

          string strOldUrl=Path.Combine(strOldFiel, str_url);

          string strNewUrl=Path.Combine(strNewFiel, "cut" + DateTime.Now.ToString("yyyyMMddHHmmss") + "." + str_url.Split('.')[1]);

          if (!Directory.Exists(strNewFiel))

          {

          Directory.CreateDirectory(strNewFiel);

          }

          int intStartX=int.Parse(strXone);

          int intStartY=int.Parse(strYone);

          int intWidth=int.Parse(strImgWidth);

          int intHeight=int.Parse(strImgHeight);

          CutGeneratedImage(intStartX, intStartY, intWidth, intHeight, strOldUrl, strNewUrl);

          context.Response.Write("{\"status\":0,\"message\":\"裁剪成功并保存!\"}");

          }

          catch

          {

          context.Response.Write("{\"status\":1,\"message\":\"裁剪失敗!\"}");

          }

          }

          /// <summary>

          /// 裁剪圖片

          /// </summary>

          /// <param name="intWidth">要縮小裁剪圖片寬度</param>

          /// <param name="intHeight">要縮小裁剪圖片長度</param>

          /// <param name="strOldImgUrl">要處理圖片路徑</param>

          /// <param name="strNewImgUrl">處理完畢圖片路徑</param>

          public void CutGeneratedImage(int intStartX, int intStartY, int intWidth, int intHeight, string strOldImgUrl, string strNewImgUrl)

          {

          //上傳標準圖大小

          int intStandardWidth=120;

          int intStandardHeight=120;

          int intReduceWidth=0; // 縮小的寬度

          int intReduceHeight=0; // 縮小的高度

          int intCutOutWidth=0; // 裁剪的寬度

          int intCutOutHeight=0; // 裁剪的高度

          int level=100; //縮略圖的質量 1-100的范圍

          //獲得縮小,裁剪大小

          if (intStandardHeight * intWidth / intStandardWidth > intHeight)

          {

          intReduceWidth=intWidth;

          intReduceHeight=intStandardHeight * intWidth / intStandardWidth;

          intCutOutWidth=intWidth;

          intCutOutHeight=intHeight;

          }

          else if (intStandardHeight * intWidth / intStandardWidth < intHeight)

          {

          intReduceWidth=intStandardWidth * intHeight / intStandardHeight;

          intReduceHeight=intHeight;

          intCutOutWidth=intWidth;

          intCutOutHeight=intHeight;

          }

          else

          {

          intReduceWidth=intWidth;

          intReduceHeight=intHeight;

          intCutOutWidth=intWidth;

          intCutOutHeight=intHeight;

          }

          //通過連接創建Image對象

          //System.Drawing.Image oldimage=System.Drawing.Image.FromFile(strOldImgUrl);

          //oldimage.Save(Server.MapPath("tepm.jpg"));

          //oldimage.Dispose();

          //縮小圖片

          Bitmap bm=new Bitmap(strOldImgUrl);

          //處理JPG質量的函數

          ImageCodecInfo[] codecs=ImageCodecInfo.GetImageEncoders();

          ImageCodecInfo ici=null;

          foreach (ImageCodecInfo codec in codecs)

          {

          if (codec.MimeType=="image/jpeg")

          {

          ici=codec;

          break;

          }

          }

          EncoderParameters ep=new EncoderParameters();

          ep.Param[0]=new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)level);

          //裁剪圖片

          Rectangle cloneRect=new Rectangle(intStartX, intStartY, intCutOutWidth, intCutOutHeight);

          PixelFormat format=bm.PixelFormat;

          Bitmap cloneBitmap=bm.Clone(cloneRect, format);

          //保存圖片

          cloneBitmap.Save(strNewImgUrl, ici, ep);

          bm.Dispose();

          }

          public bool IsReusable

          {

          get

          {

          return false;

          }

          }

          }



          4、最后奉上Demo

           https://files.cnblogs.com/files/lengzhan/ImgJcrop.zip

          讀目錄

          • 利用表單實現文件上傳
          • 表單異步上傳(jquery.form插件)
          • 模擬表單數據上傳(FormData)
          • 分片上傳
          • 使用HTML5 拖拽、粘貼上傳
          • 上傳插件(WebUploader)
          • 總結

          作為程序員的我們,經常要用到文件的上傳和下載功能。到了需要用的時候,各種查資料。有木有..有木有...。為了方便下次使用,這里來做個總結和備忘。

          利用表單實現文件上傳

          最原始、最簡單、最粗暴的文件上傳。
          前端代碼:

          //方式1
          <form action="/Home/SaveFile1" method="post" enctype="multipart/form-data">
               <input type="file" class="file1" name="file1" />
               <button type="submit" class="but1">上傳</button>
          </form>
          
          

          【注意】

          • 1、需要post提交
          • 2、enctype="multipart/form-data" (傳輸文件)
          • 3、需要提交的表單元素需要設置 name 屬性

          后臺代碼:

          public ActionResult SaveFile1()
          {
              if (Request.Files.Count > 0)
              {
                  Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Request.Files[0].FileName);
                  return Content("保存成功");
              }
              return Content("沒有讀到文件");
          }
          

          表單異步上傳(jquery.form插件)

          雖然上面的方式簡單粗暴,但是不夠友好。頁面必然會刷新。難以實現停留在當前頁面,并給出文件上傳成功的提示。
          隨著時間的流逝,技術日新月異。ajax的出現,使得異步文件提交變得更加容易。
          下面我們利用jquery.form插件來實現文件的異步上傳。
          首先我們需要導入
          jquery.jsjquery.form.js
          前端代碼:

          <form id="form2" action="/Home/SaveFile2" method="post" enctype="multipart/form-data">
              <input type="file" class="file1" name="file1" />
              <button type="submit" class="but1">上傳1</button>
              <button type="button" class="but2">上傳2</button>
          </form>
          
          
          //方式2(通過ajaxForm綁定ajax操作)
          $(function () {
              $('#form2').ajaxForm({
                  success: function (responseText) {
                      alert(responseText);
                  }
              });
          });
          
          //方式3(通過ajaxSubmit直接執行ajax操作)
          $(function () {
              $(".but2").click(function () {
                  $('#form2').ajaxSubmit({
                      success: function (responseText) {
                          alert(responseText);
                      }
                  });
              });
          });
          
          

          后臺代碼:

          public string SaveFile2()
          {
              if (Request.Files.Count > 0)
              {                
                  Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
                  return "保存成功";
              }
              return "沒有讀到文件";
          }
          

          原理:
          我們很多時候使用了插件,就不管其他三七二十一呢。
          如果有點好奇心,想想這個插件是怎么實現的。隨便看了看源碼一千五百多行。我的媽呀,不就是個異步上傳的嗎,怎么這么復雜。
          難以看出個什么鬼來,直接斷點調試下吧。


          原來插件內部有iframe和FormData不同方式來上傳,來適應更多版本瀏覽器。

          模擬表單數據上傳(FormData)

          iframe這東西太惡心。我們看到上面可以利用FormData來上傳文件,這個是Html 5 才有的。下面我們自己也來試試吧。
          前端代碼:

          <input id="fileinfo" type="file" class="notFormFile" />
          <button type="button" class="btnNotForm">上傳4</button>
          
          //方式4
          $(".btnNotForm").click(function () {
              var formData=new FormData();//初始化一個FormData對象
              formData.append("files", $(".notFormFile")[0].files[0]);//將文件塞入FormData
              $.ajax({
                  url: "/Home/SaveFile2",
                  type: "POST",
                  data: formData,
                  processData: false,  // 告訴jQuery不要去處理發送的數據
                  contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                  success: function (responseText) {
                      alert(responseText);
                  }
              });
          });
          
          

          后面的代碼:(不變,還是上例代碼)

          public string SaveFile2()
          {
              if (Request.Files.Count > 0)
              {                
                  Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
                  return "保存成功";
              }
              return "沒有讀到文件";
          }
          

          我們看到,FormData對象也只是在模擬一個原始的表單格式的數據。那有沒有可能利用表單或表單格式來上傳文件呢?答案是肯定的。(下面馬上揭曉)
          前端代碼:

          <input type="file"  id="file5" multiple>
          <button type="button" class="btnFile5">上傳5</button>    
          
          
          //方式5
          $(".btnFile5").click(function () {
              $.ajax({
                  url: "/Home/SaveFile4",
                  type: "POST",
                  data: $("#file5")[0].files[0],
                  processData: false,  // 告訴jQuery不要去處理發送的數據
                  contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                  success: function (responseText) {
                      alert(responseText);
                  }
              });;       
          });       
               
          

          后臺代碼:

          public string SaveFile4()
          {
              //這里發現只能得到一個網絡流,沒有其他信息了。(比如,文件大小、文件格式、文件名等)
              Request.SaveAs(Server.MapPath("~/App_Data/SaveFile4.data") + "", false);
              return "保存成功";
          }
          

          細心的你發現沒有了表單格式,我們除了可以上傳文件流數據外,不能再告訴后臺其他信息了(如文件格式)。
          到這里,我似乎明白了以前上傳文件為什么非得要用個form包起來,原來這只是和后臺約定的一個傳輸格式而已。
          其實我們單純地用jq的ajax傳輸文本數據的時候,最后也是組裝成了form格式的數據,如:

           $.ajax({
              data: { "userName": "張三" } 
          

          分片上傳

          在知道了上面的各種上傳之后,我們是不是就滿于現狀了呢?no,很多時候我們需要傳輸大文件,一般服務器都會有一定的大小限制。
          某天,你發現了一個激情小電影想要分享給大家。無奈,高清文件太大傳不了,怎么辦?我們可以化整為零,一部分一部分的傳嘛,也就是所謂的分片上傳。
          前端代碼:

          <input type="file" id="file6" multiple>
          <button type="button" class="btnFile6">分片上傳6</button>
          <div class="result"></div>
          
          
          //方式6
           $(".btnFile6").click(function () { 
               var upload=function (file, skip) {
                   var formData=new FormData();//初始化一個FormData對象
                   var blockSize=1000000;//每塊的大小
                   var nextSize=Math.min((skip + 1) * blockSize, file.size);//讀取到結束位置             
                   var fileData=file.slice(skip * blockSize, nextSize);//截取 部分文件 塊
                   formData.append("file", fileData);//將 部分文件 塞入FormData
                   formData.append("fileName", file.name);//保存文件名字
                   $.ajax({
                       url: "/Home/SaveFile6",
                       type: "POST",
                       data: formData,
                       processData: false,  // 告訴jQuery不要去處理發送的數據
                       contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                       success: function (responseText) {
                           $(".result").html("已經上傳了" + (skip + 1) + "塊文件");
                           if (file.size <=nextSize) {//如果上傳完成,則跳出繼續上傳
                               alert("上傳完成");
                               return;
                           }
                           upload(file, ++skip);//遞歸調用
                       }
                   });
               };
          
               var file=$("#file6")[0].files[0];
               upload(file, 0);
           }); 
          
          

          后臺代碼:

          public string SaveFile6()
          {
              //保存文件到根目錄 App_Data + 獲取文件名稱和格式
              var filePath=Server.MapPath("~/App_Data/") + Request.Form["fileName"];
              //創建一個追加(FileMode.Append)方式的文件流
              using (FileStream fs=new FileStream(filePath, FileMode.Append, FileAccess.Write))
              {
                  using (BinaryWriter bw=new BinaryWriter(fs))
                  {
                      //讀取文件流
                      BinaryReader br=new BinaryReader(Request.Files[0].InputStream);
                      //將文件留轉成字節數組
                      byte[] bytes=br.ReadBytes((int)Request.Files[0].InputStream.Length);
                      //將字節數組追加到文件
                      bw.Write(bytes);
                  }
              }
              return "保存成功";
          }
          

          相對而言,代碼量多了一點,復雜了一點。不過相對于網上的其他分片上傳的代碼應該要簡單得多(因為這里沒有考慮多文件塊同時上傳、斷點續傳。那樣就需要在后臺把文件塊排序,然后上傳完成按序合并,然后刪除原來的臨時文件。有興趣的同學可以自己試試,稍候在分析上傳插件webuploader的時候也會實現)。
          效果圖:


          【說明】:如果我們想要上傳多個文件怎么辦?其實H5中也提供了非常簡單的方式。直接在
          input里面標記multiple<input type="file" id="file6" multiple>,然后我們后臺接收的也是一個數組Request.Files

          使用HTML5 拖拽、粘貼上傳

          只能說H5真是強大啊,權限越來越大,操作越來越牛逼。
          前端代碼(拖拽上傳):

          <textarea class="divFile7" style="min-width:800px;height:150px" placeholder="請將文件拖拽或直接粘貼到這里"></textarea>
          
          //方式7
           $(".divFile7")[0].ondrop=function (event) {
          
               event.preventDefault();//不要執行與事件關聯的默認動作
               var files=event.dataTransfer.files;//獲取拖上來的文件
          
               //以下代碼不變
               var formData=new FormData();//初始化一個FormData對象
               formData.append("files", files[0]);//將文件塞入FormData
               $.ajax({
                   url: "/Home/SaveFile2",
                   type: "POST",
                   data: formData,
                   processData: false,  // 告訴jQuery不要去處理發送的數據
                   contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                   success: function (responseText) {
                       alert(responseText);
                   }
               });
           };
          
          

          后臺代碼:
          略(和之前的SaveFile2一樣)

          前端代碼(粘貼上傳 限圖片格式):

          //方式8
          $(".divFile7")[0].onpaste=function (event) {
              event.preventDefault();//不要執行與事件關聯的默認動作
              var clipboard=event.clipboardData.items[0];//剪貼板數據
              if (clipboard.kind=='file' || clipboard.type.indexOf('image') > -1) {//判斷是圖片格式
                  var imageFile=clipboard.getAsFile();//獲取文件
          
                  //以下代碼不變
                  var formData=new FormData;
                  formData.append('files', imageFile);
                  formData.append('fileName', "temp.png");//這里給文件命個名(或者直接在后臺保存的時候命名)
                  $.ajax({
                      url: "/Home/SaveFile8",
                      type: "POST",
                      data: formData,
                      processData: false,  // 告訴jQuery不要去處理發送的數據
                      contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                      success: function (responseText) {
                          alert(responseText);
                      }
                  });
              }
          };
          
          

          后臺代碼:

          public string SaveFile8()
          {
              //保存文件到根目錄 App_Data + 獲取文件名稱和格式
              var filePath=Server.MapPath("~/App_Data/") + Request.Form["fileName"];      
              if (Request.Files.Count > 0)
              {
                  Request.Files[0].SaveAs(filePath);
                  return "保存成功";
              }
              return "沒有讀到文件";
          }
          
          

          效果圖:

          上傳插件(WebUploader)

          已經列舉分析了多種上傳文件的方式,我想總有一種適合你。不過,上傳這個功能比較通用,而我們自己寫的可能好多情況沒有考慮到。接下來簡單介紹下百度的WebUploader插件。
          比起我們自己寫的簡單上傳,它的優勢:穩定、兼容性好(有flash切換,所以支持IE)、功能多、并發上傳、斷點續傳(主要還是靠后臺配合)。
          官網:http://fex.baidu.com/webuploader/
          插件下載:https://github.com/fex-team/webuploader/releases/download/0.1.5/webuploader-0.1.5.zip
          下面開始對WebUploader的使用
          第一種,簡單粗暴
          前端代碼:

          <div id="picker">選擇文件</div>
          <button id="ctlBtn" class="btn btn-default">開始上傳</button>
          
          
          <!--引用webuploader的js和css-->
          <link href="~/Scripts/webuploader-0.1.5/webuploader.css" rel="stylesheet" />
          <script src="~/Scripts/webuploader-0.1.5/webuploader.js"></script>
          <script type="text/javascript">
              var uploader=WebUploader.create({
          
                  // (如果是新瀏覽器 可以不用 flash)
                  //swf: '/Scripts/webuploader-0.1.5/Uploader.swf',
          
                  // 文件接收服務端。
                  server: '/Webuploader/SaveFile',
          
                  // 選擇文件的按鈕。可選。
                  // 內部根據當前運行是創建,可能是input元素,也可能是flash.
                  pick: '#picker'
              });
          
              $("#ctlBtn").click(function () {
                  uploader.upload();
              });
          
              uploader.on('uploadSuccess', function (file) {
                  alert("上傳成功");
              });
          
          </script>
          
          

          后臺代碼:

          public string SaveFile()
          {
              if (Request.Files.Count > 0)
              {
                  Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName));
                  return "保存成功";
              }
              return "沒有讀到文件";
          }
          

          第二種,分片上傳。和我們之前自己寫的效果差不多。
          前端代碼:

          var uploader=WebUploader.create({ 
              //兼容老版本IE
              swf: '/Scripts/webuploader-0.1.5/Uploader.swf', 
              // 文件接收服務端。
              server: '/Webuploader/SveFile2', 
              // 開起分片上傳。
              chunked: true, 
              //分片大小
              chunkSize: 1000000, 
              //上傳并發數
              threads: 1,
              // 選擇文件的按鈕。 
              pick: '#picker'
          });
          
          // 點擊觸發上傳
          $("#ctlBtn").click(function () {
              uploader.upload();
          });
          
          uploader.on('uploadSuccess', function (file) {
              alert("上傳成功");
          });
          
          

          后臺代碼:

          public string SveFile2()
          {
              //保存文件到根目錄 App_Data + 獲取文件名稱和格式
              var filePath=Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName);
              //創建一個追加(FileMode.Append)方式的文件流
              using (FileStream fs=new FileStream(filePath, FileMode.Append, FileAccess.Write))
              {
                  using (BinaryWriter bw=new BinaryWriter(fs))
                  {
                      //讀取文件流
                      BinaryReader br=new BinaryReader(Request.Files[0].InputStream);
                      //將文件留轉成字節數組
                      byte[] bytes=br.ReadBytes((int)Request.Files[0].InputStream.Length);
                      //將字節數組追加到文件
                      bw.Write(bytes);
                  }
              }
              return "保存成功";
          }
          

          我們看到了有個參數threads: 1上傳并發數,如果我們改成大于1會怎樣?前端會同時發起多個文件片上傳。后臺就會報錯,多個進程同時操作一個文件。
          那如果我們想要多線程上傳怎么辦?改代碼吧(主要是后臺邏輯)。
          前端代碼:

          //并發上傳(多線程上傳)
          var uploader=WebUploader.create({
              //兼容老版本IE
              swf: '/Scripts/webuploader-0.1.5/Uploader.swf',
              // 文件接收服務端。
              server: '/Webuploader/SveFile3',
              // 開起分片上傳。
              chunked: true,
              //分片大小
              chunkSize: 1000000,
              //上傳并發數
              threads: 10,
              // 選擇文件的按鈕。
              pick: '#picker'
          });
          
          // 點擊觸發上傳
          $("#ctlBtn").click(function () {
              uploader.upload();
          });
          
          uploader.on('uploadSuccess', function (file) {
              //上傳完成后,給后臺發送一個合并文件的命令
              $.ajax({
                  url: "/Webuploader/FileMerge",
                  data: { "fileName": file.name },
                  type: "post",
                  success: function () {
                      alert("上傳成功");
                  }
              });
          });
          
          

          后臺代碼:

          public string SveFile3()
          {
              var chunk=Request.Form["chunk"];//當前是第多少片 
          
              var path=Server.MapPath("~/App_Data/") + Path.GetFileNameWithoutExtension(Request.Files
              if (!Directory.Exists(path))//判斷是否存在此路徑,如果不存在則創建
              {
                  Directory.CreateDirectory(path);
              }
              //保存文件到根目錄 App_Data + 獲取文件名稱和格式
              var filePath=path + "/" + chunk;
              //創建一個追加(FileMode.Append)方式的文件流
              using (FileStream fs=new FileStream(filePath, FileMode.Append, FileAccess.Write))
              {
                  using (BinaryWriter bw=new BinaryWriter(fs))
                  {
                      //讀取文件流
                      BinaryReader br=new BinaryReader(Request.Files[0].InputStream);
                      //將文件留轉成字節數組
                      byte[] bytes=br.ReadBytes((int)Request.Files[0].InputStream.Length);
                      //將字節數組追加到文件
                      bw.Write(bytes);
                  }
              }           
              return "保存成功";
          }
          
          /// <summary>
          /// 合并文件
          /// </summary>
          /// <param name="path"></param>
          /// <returns></returns>
          public bool FileMerge()
          {
              var fileName=Request.Form["fileName"];
              var path=Server.MapPath("~/App_Data/") + Path.GetFileNameWithoutExtension(fileName);
          
              //這里排序一定要正確,轉成數字后排序(字符串會按1 10 11排序,默認10比2小)
              foreach (var filePath in Directory.GetFiles(path).OrderBy(t=> int.Parse(Path.GetFileNameWithoutExtension(t))))
              {
                  using (FileStream fs=new FileStream(Server.MapPath("~/App_Data/") + fileName, FileMode.Append, FileAccess.Write))
                  {
                      byte[] bytes=System.IO.File.ReadAllBytes(filePath);//讀取文件到字節數組
                      fs.Write(bytes, 0, bytes.Length);//寫入文件
                  }
                  System.IO.File.Delete(filePath);
              }
              Directory.Delete(path);
              return true;
          }
          

          到這里你以為就結束了嗎?錯,還有好多情況沒有考慮到。如果多個用戶上傳的文件名字一樣會怎樣?如何實現斷點續傳?還沒實現選擇多個文件?不過,這里不打算繼續貼代碼了(再貼下去,代碼量越來越多了),自己也來練習練習吧。
          提供一個思路,上傳前先往數據庫插入一條數據。數據包含文件要存的路徑、文件名(用GUID命名,防止同名文件沖突)、文件MD5(用來識別下次續傳和秒傳)、臨時文件塊存放路徑、文件是否完整上傳成功等信息。
          然后如果我們斷網后再傳,首先獲取文件MD5值,看數據庫里面有沒上傳完成的文件,如果有就實現秒傳。如果沒有,看是不是有上傳了部分的。如果有接著傳,如果沒有則重新傳一個新的文件。

          總結

          之前我一直很疑惑,為什么上傳文件一定要用form包起來,現在算是大概明白了。
          最開始在javascript還不流行時,我們就可以直接使用submit按鈕提交表單數據了。表單里面可以包含文字和文件。然后隨著js和ajax的流行,可以利用ajax直接異步提交部分表單數據。這里開始我就糾結了,為什么ajax可以提交自己組裝的數據。那為什么不能直接提交文件呢。這里我錯了,ajax提交的并不是隨意的數據,最后還是組裝成了表單格式(因為后臺技術對表單格式數據的支持比較普及)。但是現有的技術還不能通過js組裝一個文件格式的表單數據。直到H5中的FormData出現,讓前端js組裝一個包含文件的表單格式數據成為了可能。所以說表單只是為了滿足和后臺“約定”的數據格式而已。

          相關推薦

          • http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html
          • http://javascript.ruanyifeng.com/htmlapi/file.html

          demo

          • https://github.com/zhaopeiym/BlogDemoCode/tree/master/上傳下載

          cikit-learn 的 datasets 模塊包含測試數據相關函數,主要包括三類:

          • datasets.load_*():獲取小規模數據集。數據包含在 datasets 里
          • datasets.fetch_*():獲取大規模數據集。需要從網絡上下載,函數的第一個參數是 data_home,表示數據集下載的目錄,默認是 ~/scikit_learn_data/。要修改默認目錄,可以修改環境變量SCIKIT_LEARN_DATA。數據集目錄可以通過datasets.get_data_home()獲取。clear_data_home(data_home=None)刪除所有下載數據。
          • datasets.make_*():本地生成數據集。

          數據集格式

          • tuple(X, y)
            本地生成的數據函數
            make_*load_svmlight_* 返回的數據是 tuple(X, y) 格式
          • Bunch
            load_*fetch_* 函數返回的數據類型是 datasets.base.Bunch,本質上是一個 dict,它的一個鍵值對,可用通過對象的屬性方式訪問。主要包含以下屬性:

          data:特征數據數組,是 n_samples * n_features的二維 numpy.ndarray 數組

          target:標簽數組,是 n_samples 的一維 numpy.ndarray 數組

          DESCR:數據描述

          feature_names:特征名

          target_names:標簽名

          獲取小數據集

          • load_boston():
            房屋特征-房價,用于regression
          • load_diabetes():
            糖尿病數據,用于regression
          • load_linnerud():
            Linnerud數據集,有多個標簽,用于 multilabel regression
          • load_iris():
            鳶尾花特征和類別,用于classification
          • load_digits([n_class]):
            手寫數字識別
          • load_sample_images():
            載入圖片數據集,共兩張圖
          • load_sample_image(name):
            載入圖片數據集中的一張圖
          • load_files(container_path, description=None, categories=None, load_content=True, shuffle=True, encoding=None, decode_error='strict', random_state=0):
            從本地目錄獲取文本數據,并根據二級目錄做分類

          獲取大數據集

          • load_mlcomp(name_or_id, set_='raw', mlcomp_root=None, **kwargs):
            從 http://mlcomp.org/ 上下載數據集
          • fetch_california_housing(data_home=None, download_if_missing=True)
          • fetch_olivetti_faces(data_home=None, shuffle=False, random_state=0, download_if_missing=True):
            Olivetti 臉部圖片數據集
          • fetch_lfw_people(data_home=None, funneled=True, resize=0.5, min_faces_per_person=0, color=False, slice_=(slice(70, 195, None), slice(78, 172, None)), download_if_missing=True):
          • fetch_lfw_pairs(subset='train', data_home=None, funneled=True, resize=0.5, color=False, slice_=(slice(70, 195, None), slice(78, 172, None)), download_if_missing=True):
            Labeled Faces in the Wild (LFW) 數據集,參考 LFW
          • fetch_20newsgroups(data_home=None, subset='train', categories=None, shuffle=True, random_state=42, remove=(), download_if_missing=True)
          • fetch_20newsgroups_vectorized(subset='train', remove=(), data_home=None):
            新聞分類數據集,數據集包含 ‘train’ 部分和 ‘test’ 部分。
          • fetch_rcv1(data_home=None, subset='all', download_if_missing=True, random_state=None, shuffle=False):
            路透社新聞語聊數據集
          • fetch_mldata(dataname, target_name='label', data_name='data', transpose_data=True, data_home=None):
            從 mldata.org 中下載數據集。參考 PASCAL network
          • mldata_filename(dataname):
            將 mldata 的數據集名轉換為下載的數據文件名
          • fetch_covtype(data_home=None, download_if_missing=True, random_state=None, shuffle=False)
            Forest covertypes 數據集

          本地生成數據

          回歸(regression)

          • make_regression(n_samples=100, n_features=100, n_informative=10, n_targets=1, bias=0.0, effective_rank=None, tail_strength=0.5, noise=0.0, shuffle=True, coef=False, random_state=None)
          • make_sparse_uncorrelated(n_samples=100, n_features=10, random_state=None)
          • make_friedman1(n_samples=100, n_features=10, noise=0.0, random_state=None)
          • make_friedman2(n_samples=100, noise=0.0, random_state=None)
          • make_friedman3(n_samples=100, noise=0.0, random_state=None)

          分類(classification)

          單標簽

          • make_classification(n_samples=100, n_features=20, n_informative=2, n_redundant=2, n_repeated=0, n_classes=2, n_clusters_per_class=2, weights=None, flip_y=0.01, class_sep=1.0, hypercube=True, shift=0.0, scale=1.0, shuffle=True, random_state=None):
            生成 classification 數據集。包含所有的設置,可以包含噪聲,偏斜的數據集
          • make_blobs(n_samples=100, n_features=2, centers=3, cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True, random_state=None):
            生成 classification 數據集。數據服從高斯分布
            centers 可以是整數,表示中心點個數,或者用列表給出每個中心點的特征值
            cluster_std 也可以是浮點數或浮點數列表
            random_state 可以是整數,表示隨機起始 seed,或者 RandomState 對象,默認使用 np.random
          • make_gaussian_quantiles(mean=None, cov=1.0, n_samples=100, n_features=2, n_classes=3, shuffle=True, random_state=None):
          • make_hastie_10_2(n_samples=12000, random_state=None):
          • make_circles(n_samples=100, shuffle=True, noise=None, random_state=None, factor=0.8):
          • make_moons(n_samples=100, shuffle=True, noise=None, random_state=None):

          多標簽

          • make_multilabel_classification(n_samples=100, n_features=20, n_classes=5, n_labels=2, length=50, allow_unlabeled=True, sparse=False, return_indicator='dense', return_distributions=False, random_state=None):
            生成 multilabel classification 數據集。

          雙聚類(bicluster)

          • make_biclusters(shape, n_clusters, noise=0.0, minval=10, maxval=100, shuffle=True, random_state=None):
          • make_checkerboard(shape, n_clusters, noise=0.0, minval=10, maxval=100, shuffle=True, random_state=None):

          流形學習(manifold learning)

          • make_s_curve(n_samples=100, noise=0.0, random_state=None)
          • make_swiss_roll(n_samples=100, noise=0.0, random_state=None)、

          可降維(decomposition)數據

          • make_low_rank_matrix(n_samples=100, n_features=100, effective_rank=10, tail_strength=0.5, random_state=None)
          • make_sparse_coded_signal(n_samples, n_components, n_features, n_nonzero_coefs, random_state=None)
          • make_spd_matrix(n_dim, random_state=None)
          • make_sparse_spd_matrix(dim=1, alpha=0.95, norm_diag=False, smallest_coef=0.1, largest_coef=0.9, random_state=None)

          處理 svmlight / libsvm 格式數據

          提供 svmlight / libsvm 格式數據的導入或導出。

          • load_svmlight_file(f, n_features=None, dtype=numpy.float64, multilabel=False, zero_based='auto', query_id=False):
            返回 (X, y, [query_id]),其中 X 是 scipy.sparse matrix,y 是 numpy.ndarray
          • load_svmlight_files(files, n_features=None, dtype=numpy.float64, multilabel=False, zero_based='auto', query_id=False)
          • dump_svmlight_file(X, y, f, zero_based=True, comment=None, query_id=None, multilabel=False)

          其他數據集網站

          UCI Machine Learning Repository:http://archive.ics.uci.edu/ml/datasets.html
          UCI KDD:http://kdd.ics.uci.edu/summary.data.type.html
          Kaggle:https://www.kaggle.com/datasets

          參考

          官方datasets包文檔:http://scikit-learn.org/stable/datasets/index.html
          API列表:http://scikit-learn.org/stable/modules/classes.html#module-sklearn.datasets


          主站蜘蛛池模板: 国产在线视频一区| 中文字幕日韩一区二区三区不卡| 国产精品免费大片一区二区| 五十路熟女人妻一区二区| 亚洲AV福利天堂一区二区三| 国产精品一区二区三区99| 亚洲国产精品一区二区成人片国内| 国产一区二区三区无码免费| 亚洲AV成人精品日韩一区| 精品视频一区二区三三区四区| 日韩精品人妻一区二区中文八零| 精品视频一区二区观看| 日韩精品一区二区三区中文版 | 国产激情一区二区三区 | 国产一国产一区秋霞在线观看| 无码人妻一区二区三区免费| 亚洲视频一区在线| 亚洲一区在线视频| 国产精品亚洲午夜一区二区三区| 无码人妻精品一区二区三区久久 | 久久一区二区三区精品| 在线观看国产一区| 变态拳头交视频一区二区| 亚洲爽爽一区二区三区| 国产高清在线精品一区二区| 亚洲国产一区明星换脸| 久久久国产一区二区三区| 久久精品一区二区三区中文字幕| 久久无码精品一区二区三区| 精品国产一区二区22| 国产日韩AV免费无码一区二区| 国精产品一区一区三区免费视频| 制服中文字幕一区二区| 国产在线无码一区二区三区视频| 台湾无码AV一区二区三区| 午夜DV内射一区二区| 日韩精品一区二区三区中文精品| 国产日本一区二区三区| 人妻无码一区二区三区| 中文字幕在线一区| 亚洲国产精品无码久久一区二区|