2011-04-08 102 views
57

我需要流的文件,這將導致保存在瀏覽器的提示。 的問題是,該文件所在的目錄中被虛擬地映射,所以我無法使用,以使用Server.Mappath確定它的實際位置。該目錄與網站不在同一位置(或者甚至是活動框上的物理服務器)。下載/從URL流文件 - asp.net

我想類似的追隨者,但是,讓我通過一個Web URL,而不是服務器文件的路徑。

我可能要結束了從配置基本路徑建設我的文件路徑,然後在路徑的其餘部分追加,但我希望我能做到這一點,而不是這樣。

var filePath = Server.MapPath(DOCUMENT_PATH); 

if (!File.Exists(filePath)) 
    return; 

var fileInfo = new System.IO.FileInfo(filePath); 
Response.ContentType = "application/octet-stream"; 
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath)); 
Response.AddHeader("Content-Length", fileInfo.Length.ToString()); 
Response.WriteFile(filePath); 
Response.End(); 
+0

你能否詳細說明你的意思「虛擬映射」什麼位?虛擬IIS文件夾可通過URL訪問? – EventHorizon 2011-04-08 15:08:44

+0

它使用VPP路徑,這是EpiServer使用的概念CMS 我們設置虛擬路徑名稱(即「/ documents /」),然後指定它應該映射的物理路徑(即「//服務器名稱/文檔」 )。系統然後在運行時創建對該目錄的此引用。您可以通過網址瀏覽文件而不會出現問題 – mp3duck 2011-04-08 15:46:12

+0

文件名確實是通過URL訪問的。我需要使用此URL來流式傳輸文件,而不是服務器路徑,因爲我無法從URL中使用MapPath來修改此文件 – mp3duck 2011-04-08 15:48:31

回答

84

你可以使用的HttpWebRequest獲取文件和流它返回給客戶端。這使您可以使用url獲取文件。這是我發現的(但不記得在哪裏給予信貸)的一個例子是

//Create a stream for the file 
    Stream stream = null; 

    //This controls how many bytes to read at a time and send to the client 
    int bytesToRead = 10000; 

    // Buffer to read bytes in chunk size specified above 
    byte[] buffer = new Byte[bytesToRead]; 

    // The number of bytes read 
    try 
    { 
     //Create a WebRequest to get the file 
     HttpWebRequest fileReq = (HttpWebRequest) HttpWebRequest.Create(url); 

     //Create a response for this request 
     HttpWebResponse fileResp = (HttpWebResponse) fileReq.GetResponse(); 

     if (fileReq.ContentLength > 0) 
     fileResp.ContentLength = fileReq.ContentLength; 

     //Get the Stream returned from the response 
     stream = fileResp.GetResponseStream(); 

     // prepare the response to the client. resp is the client Response 
     var resp = HttpContext.Current.Response; 

     //Indicate the type of data being sent 
     resp.ContentType = "application/octet-stream"; 

     //Name the file 
     resp.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); 
     resp.AddHeader("Content-Length", fileResp.ContentLength.ToString()); 

     int length; 
     do 
     { 
      // Verify that the client is connected. 
      if (resp.IsClientConnected) 
      { 
       // Read data into the buffer. 
       length = stream.Read(buffer, 0, bytesToRead); 

       // and write it out to the response's output stream 
       resp.OutputStream.Write(buffer, 0, length); 

       // Flush the data 
       resp.Flush(); 

       //Clear the buffer 
       buffer = new Byte[bytesToRead]; 
      } 
      else 
      { 
       // cancel the download if client has disconnected 
       length = -1; 
      } 
     } while (length > 0); //Repeat until no data is read 
    } 
    finally 
    { 
     if (stream != null) 
     { 
      //Close the input stream 
      stream.Close(); 
     } 
    } 
+2

沖洗的響應和重新創建緩衝器每次運行是不必要的 - 它只是減慢轉移。另外,我認爲你應該重命名一些變量(fileReq - > urlRequest,fileResp - > urlResponse)。也沒有理由創建流變量,在開始時,你應該在你使用它的地方創建它(在GetResponseStream()調用附近) – data 2012-05-11 11:06:07

+0

@data_smith爲什麼你不試試你的建議?它不會編譯。緩衝區的目的是保持Web服務器上的內存使用量。 – Paparazzi 2012-06-09 20:53:01

+3

resp在本例中沒有定義:代碼不能編譯。 – Case 2012-06-26 21:47:22

-2

你可以嘗試使用的DirectoryEntry類與IIS路徑前綴:

using(DirectoryEntry de = new DirectoryEntry("IIS://Localhost/w3svc/1/root" + DOCUMENT_PATH)) 
{ 
    filePath = de.Properties["Path"].Value; 
} 

if (!File.Exists(filePath)) 
     return; 

var fileInfo = new System.IO.FileInfo(filePath); 
Response.ContentType = "application/octet-stream"; 
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath)); 
Response.AddHeader("Content-Length", fileInfo.Length.ToString()); 
Response.WriteFile(filePath); 
Response.End(); 
3

2年後,我用了達拉斯小牛隊的答案,但我有,因爲我是鏈接到的HttpWebRequest更改爲FileWebRequest直接文件。不知道到處都是這種情況,但我想我會添加它。此外,我除去

var resp = Http.Current.Resonse

,只是用來代替Http.Current.Response無論resp被引用。

+1

完美。我剝奪了達拉的答案。我發佈我的版本低於 – 2017-07-18 16:09:15

12

我這個做了不少,我想我可以添加一個簡單的答案。我在這裏設置了一個簡單的課程,但我每天晚上都會運行這個課程來收集我所關注的公司的財務數據。

class WebPage 
{ 
    public static string Get(string uri) 
    { 
     string results = "N/A"; 

     try 
     { 
      HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri); 
      HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 

      StreamReader sr = new StreamReader(resp.GetResponseStream()); 
      results = sr.ReadToEnd(); 
      sr.Close(); 
     } 
     catch (Exception ex) 
     { 
      results = ex.Message; 
     } 
     return results; 
    } 
} 

在這種情況下,我傳遞一個url並將頁面返回爲HTML。如果你想做一些與流不同的事情,你可以輕鬆地改變它。

你使用這樣的:

string page = WebPage.Get("http://finance.yahoo.com/q?s=yhoo"); 
+0

我的情況是不同的,有一個文件管理系統,返回文件格式爲.tif格式,其中沒有發送查詢字符串。例如:[鏈接](http://1.2.3.4/docsys/getdocuments.aspx?doc=DSF16-00260132)但這種方法不起作用,任何想法是讚賞。謝謝 – 2016-06-23 05:26:40

+0

@kayhanyüksel:我試過這個鏈接,但超時了。抱歉。 – CodeChops 2016-06-28 16:41:16

7

下載地址爲字節,並轉換成字節流:

using (var client = new WebClient()) 
{ 
    var content = client.DownloadData(url); 
    using (var stream = new MemoryStream(content)) 
    { 
     ... 
    } 
} 
+0

最簡單的答案,它的工作原理。謝謝 – buffjape 2017-07-03 13:44:57

+0

雖然這看起來很簡單並且工作正常,但您需要記住,此解決方案將文件加載到您的計算機內存中。因此,如果1)數據太大或2)多個請求正在同時進行,則由於內存不足導致發生異常的機會很高。 – Benjamin 2017-09-13 07:32:39