C# 流方式下载文件(hooyes提供)
private void Real(HttpResponse response, HttpRequest request) { if (File.Exists(request.PhysicalPath)) { FileInfo file = new System.IO.FileInfo(request.PhysicalPath); response.Clear(); response.AddHeader("Content-Disposition", "filename=" + file.Name); response.AddHeader("Content-Length", file.Length.ToString()); string fileExtension = file.Extension.ToLower(); switch (fileExtension) { case ".mp3": response.ContentType = "audio/mpeg3"; break; case ".mpeg": response.ContentType = "video/mpeg"; break; case ".jpg": response.ContentType = "image/jpeg"; break; case ".bmp": response.ContentType = "image/bmp"; break; case ".gif": response.ContentType = "image/gif"; break; case ".doc": response.ContentType = "application/msword"; break; case ".css": response.ContentType = "text/css"; break; case ".html": response.ContentType = "text/html"; break; case ".htm": response.ContentType = "text/html"; break; case ".swf": response.ContentType = "application/x-shockwave-flash"; break; case ".exe": response.ContentType = "application/octet-stream"; break; case ".inf": response.ContentType = "application/x-texinfo"; break; default: response.ContentType = "application/octet-stream"; break; } response.WriteFile(file.FullName); response.End(); } else { response.Write("File Not Exists"); } } }
写入后要判断文件是否存在,判断文件是否写入完成(是否被占用)
在程序中,我们经常遇到读写文件的情况,而这个时候该文件可能被其他程序占用,那么怎么判断文件是否被占用,从而友好的提示用户呢?
这里提供一个简单的办法,他就是尝试着去读该文件,如果失败,则说明文件被占用:
public static bool IsFileOpen(string filePath) { bool result = false; System.IO.FileStream fs=null; try { fs = File.OpenWrite(filePath); fs.Close(); } catch (Exception ex) { result = true; } return result;//true 打开 false 没有打开 }
MVC文件下载
public FileContentResult GetFile(int id) { SqlDataReader rdr; byte[] fileContent = null; string mimeType = "";string fileName = ""; const string connect = @"Server=.\SQLExpress;Database=FileTest;Trusted_Connection=True;"; using (var conn = new SqlConnection(connect)) { var qry = "SELECT FileContent, MimeType, FileName FROM FileStore WHERE ID = @ID"; var cmd = new SqlCommand(qry, conn); cmd.Parameters.AddWithValue("@ID", id); conn.Open(); rdr = cmd.ExecuteReader(); if (rdr.HasRows) { rdr.Read(); fileContent = (byte[])rdr["FileContent"]; mimeType = rdr["MimeType"].ToString(); fileName = rdr["FileName"].ToString(); } } return File(fileContent, mimeType, fileName); }
在View中最简单的使用来使用这个Action只需提供一个超链接:
<a href="/GetFile/1">Click to get file</a>
如果在数据库中存储的图片是图片类型,和使用超链接不同的是,我们通过指向Controller action的一个带有src属性的<image>标签来获取:
<img src="/GetFile/1" alt="My Image" />
下面再让我们来看看使用FilePathResult(用于从硬盘提取文件)是多简单的事:
public FilePathResult GetFileFromDisk() { string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/"; string fileName = "test.txt"; return File(path + fileName, "text/plain", "test.txt"); }
而这也可以用过超链接提取:
<a href="/GetFileFromDisk">Click to get file</a>
而最后一个选择FileStreamResult也可以从磁盘中提取文件:
public FileStreamResult StreamFileFromDisk() { string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/"; string fileName = "test.txt"; return File(new FileStream(path + fileName, FileMode.Open), "text/plain", fileName); }
FilePathResult和FileStreamResult的区别是什么?我们又该如何取舍呢?主要的区别是FilePathResult使用HttpResponse.TransmitFile来将文件写入Http输出流。这个方法并不会在服务器内存中进行缓冲,所以这对于发送大文件是一个不错的选择。他们的区别很像DataReader和DataSet的区别。于此同时, TransmitFile还有一个bug,这可能导致文件传到客户端一半就停了,甚至无法传送。而FileStreamResult在这方面就很棒了。比如说:返回Asp.net Chart 控件在内存中生成的图表图片,而这并不需要将图片存到磁盘中.
项目实例(生成pdf)
// 生成账单HTML页面
private string WriteHTMLFile(string strContent)
{
string createHtmlPath = System.Web.HttpContext.Current.Server.MapPath("/BillingFiles/DownloadFiles/");
Encoding code = Encoding.GetEncoding("utf-8");
// 读取模板文件
string templateHTML = System.Web.HttpContext.Current.Server.MapPath("/BillingFiles/Template/BillingTemplate.html");
StreamReader sr = null;
StreamWriter sw = null;
string str = string.Empty;
try
{
sr = new StreamReader(templateHTML, code);
str = sr.ReadToEnd();
}
catch (Exception ex)
{
log.Error("ReadFile Error:" + ex.Message + ex.InnerException + ex.StackTrace);
sr.Close();
return null;
}
string htmlFileName = "BillingDetail_" + currentUser.AccountId + DateTime.Now.ToString("_yyyyMMddHHmmss") + ".html";
str = str.Replace("{body}", strContent);
// 写HTML文件
try
{
sw = new StreamWriter(createHtmlPath + htmlFileName, false, code);
sw.Write(str);
sw.Flush();
}
catch (Exception ex)
{
log.Error("WriteFile Error:" + ex.Message + ex.InnerException + ex.StackTrace);
sw.Close();
return null;
}
finally
{
sw.Close();
}
log.Info("Create HTML ok acctid:" + currentUser.AccountId + " FILE:" + createHtmlPath + htmlFileName);
return createHtmlPath + htmlFileName;
}
private string CreateBillingPDF(string htmlPath)
{
// 从html路径中计算生成pdf的文件名
int begin = htmlPath.IndexOf("DownloadFiles");
int end = htmlPath.IndexOf(".html");
string pdfFileName = htmlPath.Substring(begin + 14, end - begin - 14) + ".pdf";
try
{
if (string.IsNullOrEmpty(htmlPath))
return null;
string pdfPath = System.Web.HttpContext.Current.Server.MapPath("/BillingFiles/DownloadFiles/") + pdfFileName;
Process p = new Process();
string str = System.Web.HttpContext.Current.Server.MapPath("/BillingFiles/wkhtmltopdf-0.8.3.exe");
if (!System.IO.File.Exists(str))
return null;
p.StartInfo.FileName = str;
p.StartInfo.Arguments = " \"" + htmlPath + "\" " + pdfPath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
// 判断文件是否已经生成并且pdf写入完毕
bool b = true;
while (b)
{
if (System.IO.File.Exists(pdfPath))
{
if (IsFileOpen(pdfPath))
{
System.Threading.Thread.Sleep(500);
}
else
{
b = false;
}
}
else
{
System.Threading.Thread.Sleep(500);
}
}
string fileURL = String.Format("http://{0}{1}", Request.Url.Authority, Request.ApplicationPath) + "BillingFiles/DownloadFiles/" + pdfFileName;
log.Info("Create PDF ok acctid:" + currentUser.AccountId + " FILE:" + fileURL + " " + pdfPath);
return fileURL;
}
catch (Exception ex)
{
log.Error("CreatePDF Error: Acctid:" + currentUser.AccountId + ex.Message + ex.InnerException + ex.StackTrace);
}
return null;
}