• ASP.NET 大文件下载


    一、ASP.NET 内建方案

      在WEB程序中下载一个文件,最简单有效的办法就是直接给个链接到该文件的虚拟路径,把所有的问题交给浏览器和WEB服务器去处理,但这种“良好”好的解决方案也会带来一些其它问题,譬如:无法在程序中控制下载权限,无法统计下载信息,无法将文件名更改为一个对客户良好的名字(事实上,为了避免服务器中文件名的重复,我们一般会分配给文件一个很长而又没有任何实际意义的名字,这不是客户端希望看到的,所以我们有必要在下载时重新为文件分配一个有意义的名字)。

    基于上述原因,ASP.NET提供了两个方法,用于在程序中接管服务器端文件的下载,它们是:

    • Response.WriteFile
    • Response.TransmitFile

    二、为什么不使用内建方案

      上面提到的两个内建方案有其致命的局限性。WriteFile 在获取文件的路径后,会试图将文件流全部读入内存,之后再发送回客户端。对于小文件和流量很小的网站,使用这个方法或许问题不大,但如果文件很大或者网站的流量很大,使用这个方法可以让 aspnet_wp.exe 进程意味终止,导致当前服务器下所有 asp.net 站点全部瘫痪,不仅如此,服务器的物理内存也会在瞬间被填满,导致其它程序运行失败或意外终止。TransmitFile 是 WriteFile 的一个改良版本,它解决了 WriteFile 将文件流一次性全部读入内存的错误举动,修改为按某个固定的字节循环读取,但它仍然存在问题,这个问题甚至比 WriteFile 的缺点更不能让人接受。使用 TransmitFile 下载文件,浏览器(IE)竟然不会弹出路径保存窗口,而是直接下载到临时目录,而对于IE的临时目录,或许很少有人能够快速准确地找到。

    三、替代方法

    要解决上面提到的问题,可以避免使用 WriteFile 和 TransmitFile 进行文件的读取,下面都是可行的替代方法:

    • 使用 FTP 传输文件
    • 直接提供一个指向文件的链接
    • 使用 Microsoft ASP 3.0 进行下载或者与 ASP 一起使用 Software Artisans FileUp
    • 创建 ISAPI 扩展以下载文件
    • 将数据分成较小的部分,然后将其移动到输出流以供下载,从而获取这些数据

    下面提供最后一种方法的 C# 源码

    System.IO.Stream iStream = null;

    // Buffer to read 10K bytes in chunk:
    byte[] buffer = new Byte[10000];

    // Length of the file:
    int length;

    // Total bytes to read:
    long dataToRead;

    // Identify the file to download including its path.
    string filepath = "DownloadFileName";

    // Identify the file name.
    string filename = System.IO.Path.GetFileName(filepath);

    try {
        
    // Open the file.
        iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
        System.IO.FileAccess.Read, System.IO.FileShare.Read);


        
    // Total bytes to read:
        dataToRead = iStream.Length;

        Response.ContentType 
    = "application/octet-stream";
        Response.AddHeader(
    "Content-Disposition""attachment; filename=" + filename);

        
    // Read the bytes.
        while (dataToRead > 0) {
            
    // Verify that the client is connected.
            if (Response.IsClientConnected) {
                
    // Read the data in buffer.
                length = iStream.Read(buffer, 010000);

                
    // Write the data to the current output stream.
                Response.OutputStream.Write(buffer, 0, length);

                
    // Flush the data to the HTML output.
                Response.Flush();

                buffer 
    = new Byte[10000];
                dataToRead 
    = dataToRead - length;
            } 
    else {
                
    //prevent infinite loop if user disconnects
                dataToRead = -1;
            }
        }
    catch (Exception ex) {
        
    // Trap the error, if any.
        Response.Write("Error : " + ex.Message);
    finally {
        
    if (iStream != null) {
            
    //Close the file.
            iStream.Close();
        }
    }

  • 相关阅读:
    读《奇点临近》
    C++中rand()函数的用法
    第四届蓝桥杯 c/c++真题
    ACM做题过程中的一些小技巧
    树状数组
    go单元测试进阶篇
    浓缩的才是精华:浅析GIF格式图片的存储和压缩
    腾讯IVWEB团队:WebRTC 点对点直播
    Mongodb Geo2d索引原理
    Unity编译Android的原理解析和apk打包分析
  • 原文地址:https://www.cnblogs.com/wfyfngu/p/1340773.html
Copyright © 2020-2023  润新知