关于ASP.NET中输出PNG图片的说明

今天在用ASP.NET向Web请求的响应输出流中写入PNG图片时出现了“GDI+ 中发生一般性错误的异常”,使用的方法是直接将图片保存到响应输出流中,引发异常的代码是:

image.Save(Response.OutputStream, ImageFormat.Png);

究其原因是因为PNG图片的解码器需要双向流,而Response中的输出流OutputStream是无法往回读取的,即它的CanSeek属性等于false。
如果要想在该流中写入PNG图片,我们需要将图片的数据预先读取出来,然后以普通数据流的形式将其写入:

// 读取PNG图片数据到内存流
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Png);
// 将内存流的数据写入到响应输出流
memoryStream.WriteTo(Response.OutputStream);
memoryStream.Close();

关于ASP.NET中服务端实现文件下载的说明

一、TransmitFile方式下载:

// Url编码下载文件名
string fileName = HttpUtility.UrlEncode("download.txt");
// 获取文件本地物理路径
string filePath = Server.MapPath("download.txt");
// 设置文件下载响应报文
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
// 输出下载文件数据
Response.TransmitFile(filePath);

二、WriteFile方式下载:

// Url编码下载文件名
string fileName = HttpUtility.UrlEncode("download.txt");
// 获取文件本地物理路径
string filePath = Server.MapPath("download.txt");
FileInfo fileInfo = new FileInfo(filePath);
// 设置文件下载响应报文
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.AddHeader("Content-Transfer-Encoding", "binary");
Response.ContentType = "application/octet-stream";
Response.ContentEncoding = Encoding.Default;
// 输出下载文件数据
Response.WriteFile(fileInfo.FullName);
Response.Flush();
Response.End();

三、FileStream方式下载:

// Url编码下载文件名
string fileName = HttpUtility.UrlEncode("download.txt");
// 获取文件本地物理路径
string filePath = Server.MapPath("download.txt");
// 读取文件数据
FileStream fileStream = new FileStream(filePath, FileMode.Open);
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, buffer.Length);
fileStream.Close();
// 设置文件下载响应报文
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
// 输出下载文件数据
Response.BinaryWrite(buffer);
Response.Flush();
Response.End();

四、FileStream分块下载:

// Url编码下载文件名
string fileName = HttpUtility.UrlEncode("download.txt");
// 获取文件本地物理路径
string filePath = Server.MapPath("download.txt");
FileInfo fileInfo = new FileInfo(filePath);
// 设置分块大小
int bufferLength = 1024;
byte[] buffer = new byte[bufferLength];
FileStream fileStream = File.OpenRead(filePath);
long downloadLength = fileStream.Length;
// 设置文件下载响应报文
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
// 分块输出下载文件数据
while (downloadLength > 0 && Response.IsClientConnected)
{
    int readLength = fileStream.Read(buffer, 0, bufferLength);
    Response.OutputStream.Write(buffer, 0, readLength);
    Response.Flush();
    downloadLength = downloadLength - readLength;
}
fileStream.Close();
Response.End();

五、断点续传下载:

// Url编码下载文件名
string fileName = HttpUtility.UrlEncode("download.txt");
// 获取文件本地物理路径
string filePath = Server.MapPath("download.txt");
FileStream fileStream = File.OpenRead(filePath);
long startPosition = 0;
long downloadLength = fileStream.Length;
Response.Clear();
// 读取请求下载文件区段
if (Request.Headers["Range"] != null)
{
    Response.StatusCode = 206;
    string[] split = Request.Headers["Range"].Replace("bytes=", "").Split('-');
    if (split.Length <= 0 || !long.TryParse(split[0], out startPosition))
    {
        startPosition = 0;
    }
    // 设置当前文件区段响应报文
    Response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", startPosition, fileStream.Length - 1, fileStream.Length));
    downloadLength -= startPosition;
}
// 设置文件下载响应报文
Response.AddHeader("Content-Length", downloadLength.ToString());
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
// 定位区段位置读取文件区段数据
byte[] buffer = new byte[downloadLength];
fileStream.Position = startPosition;
fileStream.Read(buffer, 0, buffer.Length));
fileStream.Close();
// 输出下载文件区段数据
Response.BinaryWrite(buffer);
Response.End();