Tải lên tệp trong ASP.net mà không sử dụng điều khiển máy chủ FileUpload


99

Làm cách nào tôi có thể lấy biểu mẫu web ASP.net (v3.5) để đăng tệp bằng cách sử dụng mẫu cũ <input type="file" />?

Tôi không quan tâm đến việc sử dụng điều khiển máy chủ ASP.net FileUpload.

Câu trả lời:


133

Trong aspx của bạn:

<form id="form1" runat="server" enctype="multipart/form-data">
 <input type="file" id="myFile" name="myFile" />
 <asp:Button runat="server" ID="btnUpload" OnClick="btnUploadClick" Text="Upload" />
</form>

Trong mã phía sau:

protected void btnUploadClick(object sender, EventArgs e)
{
    HttpPostedFile file = Request.Files["myFile"];

    //check file was submitted
    if (file != null && file.ContentLength > 0)
    {
        string fname = Path.GetFileName(file.FileName);
        file.SaveAs(Server.MapPath(Path.Combine("~/App_Data/", fname)));
    }
}

3
@mathieu, đáng tiếc là bạn biến thiên không sử dụng runat="server", nó không phải là độc lập với những thứ server của ASP.NET
Bí mật

điều gì xảy ra nếu có nhiều hơn 1 đầu vào và bạn muốn các chức năng riêng biệt được thực hiện với cả hai bộ tệp.
Neville Nazerane

trong khi sử dụng nó để tải lên nhiều tệp, nó trả về cùng một tên tệp cho tất cả các tệp và do đó lưu tệp đầu tiên n số lần. Bất kỳ ý tưởng làm thế nào để vượt qua nó?
sohaiby

@Martina Kiểm tra đoạn mã này để lưu nhiều tệp
sohaiby

1
@DanielJ. Không có cách nào khả thi để không sử dụng mã phía sau nếu bạn định làm bất cứ điều gì với tệp sau đó, tức là lưu trữ nó trong cơ sở dữ liệu. Chắc chắn, bạn có thể sử dụng JavaScript đơn giản để lấy đầu vào & tệp: var fileUploaded = document.getElementById("myFile").files[0];và bạn thậm chí có thể lấy các byte bằng cách sử dụng readAsArrayBuffer: stackoverflow.com/questions/37134433/… - nhưng bạn sẽ làm gì với tất cả các byte phía máy khách đó? OP muốn tránh hoàn toàn giao tiếp phía máy chủ không điều khiển ASP .NET. -1 cho bạn.
vapcguy

40

Đây là một giải pháp mà không cần dựa vào bất kỳ điều khiển phía máy chủ nào, giống như OP đã mô tả trong câu hỏi.

Mã HTML phía máy khách:

<form action="upload.aspx" method="post" enctype="multipart/form-data">
    <input type="file" name="UploadedFile" />
</form>

Phương thức Page_Load của upload.aspx:

if(Request.Files["UploadedFile"] != null)
{
    HttpPostedFile MyFile = Request.Files["UploadedFile"];
    //Setting location to upload files
    string TargetLocation = Server.MapPath("~/Files/");
    try
    {
        if (MyFile.ContentLength > 0)
        {
            //Determining file name. You can format it as you wish.
            string FileName = MyFile.FileName;
            //Determining file size.
            int FileSize = MyFile.ContentLength;
            //Creating a byte array corresponding to file size.
            byte[] FileByteArray = new byte[FileSize];
            //Posted file is being pushed into byte array.
            MyFile.InputStream.Read(FileByteArray, 0, FileSize);
            //Uploading properly formatted file to server.
            MyFile.SaveAs(TargetLocation + FileName);
        }
    }
    catch(Exception BlueScreen)
    {
        //Handle errors
    }
}

Coi chừng cuộc gọi HTTPWebRequest gửi đường dẫn tệp đầy đủ trong MyFile.FileName. Cuộc gọi WebClient chỉ gửi tên tệp. HTTPWebRequest sẽ khiến MyFile.SaveAs bị lỗi. Chỉ lãng phí hàng giờ theo đuổi một khách hàng làm việc và một khách hàng thì không.
Bob Clegg

Tôi chỉ sử dụng Request.Files[0]thay vì Request.Files["UploadedFile"]và trong khi OP đang sử dụng ASP .NET thẳng chứ không phải MVC, nếu ai muốn sử dụng điều này cho MVC, bạn chỉ cần HttpPostedFileBasethay thế HttpPostedFile.
vapcguy

23

Bạn sẽ phải đặt enctypethuộc tính của formthành multipart/form-data; thì bạn có thể truy cập tệp đã tải lên bằng HttpRequest.Filesbộ sưu tập.


Biểu mẫu máy chủ của tôi nằm trên trang chính và tôi không thể thêm nhiều phần / biểu mẫu-dữ liệu (vì sau đó nó sẽ nằm trên mọi trang). Một cách giải quyết nhanh chóng và hiệu quả là thêm một điều khiển FileUpload ẩn vào trang. Sau đó, WebForms đã tự động thêm dữ liệu đa phần / biểu mẫu. Tôi phải làm điều này vì tôi đang sử dụng đầu vào tệp với Angular2 và không thể sử dụng điều khiển máy chủ trong mẫu thành phần.
Jason

9

sử dụng điều khiển HTML với thuộc tính máy chủ runat

 <input id="FileInput" runat="server" type="file" />

Sau đó, trong asp.net Codebehind

 FileInput.PostedFile.SaveAs("DestinationPath");

Ngoài ra còn có một số tùy chọn bên thứ 3 sẽ hiển thị tiến trình nếu bạn vướng vào


3
Một lần nữa, đó là biến nó thành một điều khiển máy chủ. ;)
ahwm

@ahwm Các OP muốn tránh sự kiểm soát ASP NET FileUpload ( <asp:FileUpload ID="fileUpload1" runat="server"></asp:FileUpload>) Đó là khác nhau hơn là nói để không đặt một runat=servertrên một inputlĩnh vực.
vapcguy

1
Tôi hiểu điều đó có nghĩa là họ không muốn sử dụng các điều khiển ASP.NET. Trong đó bao gồm HtmlInputFilekiểm soát.
ahwm

8

Có, bạn có thể đạt được điều này bằng phương pháp ajax post. về phía máy chủ, bạn có thể sử dụng httphandler. Vì vậy, chúng tôi không sử dụng bất kỳ điều khiển máy chủ nào theo yêu cầu của bạn.

với ajax, bạn cũng có thể hiển thị tiến trình tải lên.

bạn sẽ phải đọc tệp dưới dạng dòng đầu vào.

using (FileStream fs = File.Create("D:\\_Workarea\\" + fileName))
    {
        Byte[] buffer = new Byte[32 * 1024];
        int read = context.Request.GetBufferlessInputStream().Read(buffer, 0, buffer.Length);
        while (read > 0)
        {
            fs.Write(buffer, 0, read);
            read = context.Request.GetBufferlessInputStream().Read(buffer, 0, buffer.Length);
        }
    } 

Mã mẫu

function sendFile(file) {              
        debugger;
        $.ajax({
            url: 'handler/FileUploader.ashx?FileName=' + file.name, //server script to process data
            type: 'POST',
            xhr: function () {
                myXhr = $.ajaxSettings.xhr();
                if (myXhr.upload) {
                    myXhr.upload.addEventListener('progress', progressHandlingFunction, false);
                }
                return myXhr;
            },
            success: function (result) {                    
                //On success if you want to perform some tasks.
            },
            data: file,
            cache: false,
            contentType: false,
            processData: false
        });
        function progressHandlingFunction(e) {
            if (e.lengthComputable) {
                var s = parseInt((e.loaded / e.total) * 100);
                $("#progress" + currFile).text(s + "%");
                $("#progbarWidth" + currFile).width(s + "%");
                if (s == 100) {
                    triggerNextFileUpload();
                }
            }
        }
    }

2
Có lẽ bạn nên thêm gợi ý để thêm fs.close()mọi thứ khác có thể kết thúc trong các tệp không đọc được vì chúng vẫn mở bằng cách nào đó trong IIS.
nhầm

@mistapink Có phải luồng tệp không bị đóng khi quá trình thực thi rời khỏi khối đang sử dụng không?
Sebi

@Sebi hình như gần 3 năm trước thì không. Không thử trong một thời gian dài, vì vậy tôi không thể đưa ra câu trả lời chắc chắn ở đây. Tôi xin lỗi.
nhầm

4

Bộ sưu tập Request.Files chứa bất kỳ tệp nào được tải lên cùng với biểu mẫu của bạn, bất kể chúng đến từ điều khiển FileUpload hay được viết thủ công <input type="file">.

Vì vậy, bạn chỉ có thể viết một thẻ đầu vào tệp cũ thuần túy ở giữa WebForm của mình, sau đó đọc tệp được tải lên từ bộ sưu tập Request.Files.


4

Như những người khác đã trả lời, Request.Files là một HttpFileCollection chứa tất cả các tệp đã được đăng, bạn chỉ cần yêu cầu đối tượng đó cho tệp như sau:

Request.Files["myFile"]

Nhưng điều gì sẽ xảy ra khi có nhiều đánh dấu đầu vào có cùng tên thuộc tính:

Select file 1 <input type="file" name="myFiles" />
Select file 2 <input type="file" name="myFiles" />

Ở phía máy chủ, mã trước đó Request.Files ["myFile"] chỉ trả về một đối tượng HttpPostedFile thay vì hai tệp. Tôi đã thấy trên .net 4.5 một phương thức mở rộng được gọi là GetMultiple nhưng đối với các phiên bản thịnh hành thì nó không tồn tại, vì vấn đề đó, tôi đề xuất phương thức mở rộng là:

public static IEnumerable<HttpPostedFile> GetMultiple(this HttpFileCollection pCollection, string pName)
{
        for (int i = 0; i < pCollection.Count; i++)
        {
            if (pCollection.GetKey(i).Equals(pName))
            {
                yield return pCollection.Get(i);
            }
        }
}

Phương thức mở rộng này sẽ trả về tất cả các đối tượng HttpPostedFile có tên "myFiles" trong HttpFileCollection nếu có.


2

Kiểm soát HtmlInputFile

Tôi đã sử dụng cái này mọi lúc.


2
Điều đó đòi hỏi phải thêm vào runat="server"mà về cơ bản biến nó thành một điều khiển máy chủ mà họ không muốn sử dụng.
ahwm

@ahwm Không, OP không muốn sử dụng điều khiển ASP .NET FileUpload cụ thể. Nói chung, điều đó khác với việc nói rằng họ không muốn sử dụng điều khiển phía máy chủ.
vapcguy


0
//create a folder in server (~/Uploads)
 //to upload
 File.Copy(@"D:\CORREO.txt", Server.MapPath("~/Uploads/CORREO.txt"));

 //to download
             Response.ContentType = ContentType;
             Response.AppendHeader("Content-Disposition", "attachment;filename=" + Path.GetFileName("~/Uploads/CORREO.txt"));
             Response.WriteFile("~/Uploads/CORREO.txt");
             Response.End();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.