Response.BinaryWrite向客户端发送大文件

有时候我们需要向客户端发送文件,可以增加HTTP头Content-Disposition", "attachment; filename=fname.ext",然后用Response.BinaryWrite来向客户端写入二进制流,但这时候有个问题,IIS允许的写入最大应该是2M左右,当然具体多大我没有测过,但20M以上的绝对不可能写入,这个问题我摸索了几个小时,最后想到了C/S模式的客户端对服务器端的模式,然后测试,成功了。

以下是具体的代码:
先是ASP JScript版
引用内容 引用内容

<%
function sendFileToClient(filepath)
{
    filepath = filepath.replace(/^\s+|\s+$/g, "");
    
    Response.Buffer = true;  //打开buffer后,不知道效率会不会更高,你可以注释掉测试一下,注意下面的Clear(); Flush();也要一同注释掉。
    Response.Clear();
    
    var s = Server.CreateObject("ADODB.Stream");
    s.Type = 1; //以binary打开
    s.Open();
    
    var filetype, filesize, filename, ContentType;
    var fso;
    var fileLen;
    var file;
    try
    {
        fso = Server.CreateObject("Scripting.FileSystemObject"); //创建FSO取得文件名,文件大小(其实不需要,直接用ADO就有size属性了。
        file = fso.GetFile(filepath);
        filename = file.name;
        filesize = file.size;
        
        filetype = filename.substring(filename.lastIndexOf(".")) || "";
        switch(filetype.toLowerCase()) //根据文件后缀取得默认的MIME头
        {
            case ".asf":
                ContentType = "video/x-ms-asf";
                break;
            case ".avi":
                ContentType = "video/avi";
                break;
            case ".doc":
                ContentType = "application/msword";
                break;
            case ".zip":
                ContentType = "application/zip";
                break;
            case ".xls":
                ContentType = "application/vnd.ms-excel";
                break;
            case ".gif":
                ContentType = "image/gif";
                break;
            case ".jpg":
            case ".jpeg":
                ContentType = "image/jpeg";
                break;
            case ".wav":
                ContentType = "audio/wav";
                break;
            case ".mp3":
                ContentType = "audio/mpeg3";
                break;
            case ".mpg":
            case ".mpeg":
                ContentType = "video/mpeg";
                break;
            case ".rtf":
                ContentType = "application/rtf";
                break;
            case ".htm":
            case ".html":
                ContentType = "text/html";
                break;
            case ".txt":
                ContentType = "text/plain";
                break;
            default:
                ContentType = "application/octet-stream";
        }
        
        s.LoadFromFile(filepath); //将文件加载入ADO
    }
    catch(e)
    {
        Response.Write(e.description);
        Response.End();
    }
    
    Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); //增加“附加”文件的头信息,并指明文件名
    Response.AddHeader("Content-Length", filesize); //增加文件大小
    Response.CharSet = "UTF-8"; //这个要不要无所谓
    Response.ContentType = ContentType; //增加MIME头
    
    var bufferSize = 1048576; //指定每次向客户端写入多大的流,这里是1M
    var cursor = 0;
    s.Position = cursor; //ADO流的当前位置
    
    while(true)
    {
        if((cursor + bufferSize) < filesize) //如果当前还没有读完
        {
            Response.BinaryWrite(s.Read(bufferSize)); //那么向客户端写入指定大小的数据
            cursor += bufferSize;
            s.Position = cursor;  //ADO流位置向前增加
        }
        else  //否则当前不够读取指定BUFFER的大小
        {
            Response.BinaryWrite(s.Read(filesize - cursor));   //读取剩下的数据
            cursor += filesize - cursor;
            break;   //数据已读完,退出循环
        }
        
        Response.Flush();  //这个如果上面注释了Response.Buffer = true; 那么要把这个也注释掉,不知道哪个的效率更高些。
    }
    
    Response.Clear();
    
    file = null;   //注销对象
    fso = null;
    s.Close();
    s = null;
}
%>


再是ASP VBScript版,下面的大部分注释都省略了,和上面的是一样的,不同的地方才写了注释
引用内容 引用内容

<%
Sub sendFileToClient(ByVal filepath)
    filepath = Trim(filepath)
    
    'Response.Buffer = true   '注释掉了
    Response.Buffer = false
    'Response.Clear
    
    Dim s
    Set s = Server.CreateObject("ADODB.Stream")
    s.Type = 1
    s.Open
    
    Dim filetype, filesize, filename, ContentType
    Dim fso
    Dim fileLen
    Dim file
    
    On Error Resume Next
    
    Set fso = Server.CreateObject("Scripting.FileSystemObject")
    Set file = fso.GetFile(filepath)
    filename = file.name
    filesize = file.size
        
    filetype = Mid(filename, InStrRev(filename, "."), Len(filename))
    if IsEmpty(filetype) or IsNull(filetype) Then filetype = ""
    
    Select Case LCase(filetype)
        case ".asf"
            ContentType = "video/x-ms-asf"
        case ".avi"
            ContentType = "video/avi"
        case ".doc"
            ContentType = "application/msword"
        case ".zip"
            ContentType = "application/zip"
        case ".xls"
            ContentType = "application/vnd.ms-excel"
        case ".gif"
            ContentType = "image/gif"
        case ".jpg"
        case ".jpeg"
            ContentType = "image/jpeg"
        case ".wav"
            ContentType = "audio/wav"
        case ".mp3"
            ContentType = "audio/mpeg3"
        case ".mpg"
        case ".mpeg"
            ContentType = "video/mpeg"
        case ".rtf"
            ContentType = "application/rtf"
        case ".htm"
        case ".html"
            ContentType = "text/html"
        case ".txt"
            ContentType = "text/plain"
        case else
            ContentType = "application/octet-stream"
    End Select
    
    s.LoadFromFile(filepath)
    
    If Err <> 0 Then
        Response.Write Err.description
        Err.Clear
        Response.End
    End If
    
    Response.CharSet = "UTF-8"
    Response.AddHeader "Content-Disposition", "attachment; filename=""" & filename & """;"
    Response.AddHeader "Content-Length", filesize
    Response.ContentType = ContentType
    
    '只有这里有点不同,其实上面的JS版里面也可以直接用:
    'for(var i = 0; i < Math.ceil(filesize / bufferSize); i++)
    '{
    '    Response.BinaryWrite(s.Read(bufferSize));
    '}
    '也是一样的,只不过按JScript版本那样写是一种好习惯(规范一些),因为ASP里面的ADO有兼容,如果游标超出FILE_POS会自动读取至结尾,ADO的游标也会自动前进,但其它有些语言就不会这样了,会出错,在这里就直接偷懒吧

    Dim i, bufferSize : bufferSize = 1048576
    s.Position = 0
    
    '直接偷懒
    For i = 0 To filesize \ bufferSize
        Response.BinaryWrite(s.Read(bufferSize))
    Next
    
    'Response.Clear();
    
    Set file = Nothing
    Set fso = Nothing
    s.Close
    Set s = Nothing
End Sub
%>


欢迎转载,但转载请注意保留原博客及作者信息
作者:JC
MSN:rot-apple@hotmail.com
Skype:ctv_jcyuan
博客:http://www.jc-space.com/blog



评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.