2010-09-23 45 views
22

Trong C# ASP.net, ai đó có thể chỉ cho tôi cách tôi có thể viết các mục từ một mảng/danh sách vào một tệp CSV trên máy chủ và sau đó mở tệp? Tôi nghĩ rằng phần thứ hai sẽ là một cái gì đó như - Response.Redirect ("http://myserver.com/file.csv"), tuy nhiên không chắc chắn về cách viết các tập tin trên máy chủ.Ghi vào tệp CSV và xuất tệp đó?

Ngoài ra nếu trang này được nhiều người dùng truy cập, tốt hơn là tạo tệp CSV mới mỗi lần hoặc ghi đè lên cùng một tệp? Sẽ có bất kỳ vấn đề về đọc/ghi/khóa nào nếu cả hai người dùng thử truy cập cùng một tệp CSV, v.v.?


Cập nhật:

Đây có lẽ là một câu hỏi ngớ ngẩn và tôi đã tìm kiếm trên Google nhưng tôi không thể tìm thấy một câu trả lời dứt khoát - làm thế nào để bạn viết một tập tin CSV để các máy chủ web và xuất khẩu nó trong C# ASP.net? Tôi biết làm thế nào để tạo ra nó nhưng tôi muốn lưu nó vào www.mysite.com/my.csv và sau đó xuất nó.

+0

Tệp CSV có luôn giống với tất cả người dùng không? – TheGeekYouNeed

Trả lời

47

Rom, bạn đang làm nó sai. Bạn không muốn ghi tập tin vào đĩa để IIS có thể phục vụ chúng. Điều đó bổ sung thêm các tác động an ninh cũng như tăng độ phức tạp. Tất cả những gì bạn thực sự cần làm là lưu CSV trực tiếp vào luồng phản hồi.

Đây là kịch bản: Người dùng muốn tải xuống csv. Người dùng gửi biểu mẫu có thông tin chi tiết về csv mà họ muốn. Bạn chuẩn bị csv, sau đó cung cấp cho người dùng một URL đến một trang aspx có thể được sử dụng để xây dựng tệp csv và ghi nó vào luồng phản hồi. Người dùng nhấp vào liên kết. Trang aspx trống; trong trang codebehind bạn chỉ cần viết csv vào luồng phản hồi và kết thúc nó.

Bạn có thể thêm dòng sau vào (Tôi tin rằng điều này là đúng) Load sự kiện:

string attachment = "attachment; filename=MyCsvLol.csv"; 
HttpContext.Current.Response.Clear(); 
HttpContext.Current.Response.ClearHeaders(); 
HttpContext.Current.Response.ClearContent(); 
HttpContext.Current.Response.AddHeader("content-disposition", attachment); 
HttpContext.Current.Response.ContentType = "text/csv"; 
HttpContext.Current.Response.AddHeader("Pragma", "public"); 

var sb = new StringBuilder(); 
foreach(var line in DataToExportToCSV) 
    sb.AppendLine(TransformDataLineIntoCsv(line)); 

HttpContext.Current.Response.Write(sb.ToString()); 

bằng văn bản cho phản ứng suối đang ganked from here.

+1

Sử dụng Response.End() một cách thận trọng. Thông tin thêm: http://stackoverflow.com/questions/1087777/is-response-end-considered-harmful –

1

Làm thế nào để viết thư cho một tập tin (tìm kiếm dễ dàng trong Google) ... 1st Search Result

Theo như tạo ra các tập tin mỗi khi người dùng truy cập vào trang ... mỗi truy cập sẽ hành động thay mặt riêng của nó. Bạn kinh doanh trường hợp sẽ dictate hành vi.

Trường hợp 1 - cùng một tập tin nhưng không thay đổi (loại trường hợp có thể có nhiều cách để được xác định)

  • Bạn sẽ có logic đã tạo ra các tập tin khi cần thiết và chỉ truy cập vào các tập tin nếu thế hệ là không cần thiết.

Trường hợp 2 - mỗi người dùng cần để tạo ra tập tin riêng của họ

  • Bạn sẽ quyết định cách bạn xác định mỗi người dùng, tạo ra một tập tin cho mỗi người dùng và truy cập các tập tin họ có nghĩa vụ để xem ... điều này có thể dễ dàng hợp nhất với Case 1. Sau đó, bạn xóa các tập tin sau khi phục vụ nội dung hay không nếu nó đòi hỏi sự kiên trì.

Trường hợp 3 - cùng một tập tin nhưng thế hệ cần thiết cho mỗi truy cập

  • Trường hợp sử dụng 2, điều này sẽ gây ra một thế hệ mỗi lần nhưng dọn dẹp một lần truy cập.
4

Dưới đây là kết quả hành động CSV mà tôi đã viết có một DataTable và chuyển đổi nó thành CSV. Bạn có thể trả lại điều này từ chế độ xem của bạn và nó sẽ nhắc người dùng tải xuống tệp. Bạn sẽ có thể chuyển đổi dễ dàng thành dạng tương thích với Danh sách hoặc thậm chí chỉ cần đưa danh sách của bạn vào một DataTable.

using System; 
using System.Text; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Data; 

namespace Detectent.Analyze.ActionResults 
{ 
    public class CSVResult : ActionResult 
    { 
     /// <summary> 
     /// Converts the columns and rows from a data table into an Microsoft Excel compatible CSV file. 
     /// </summary> 
     /// <param name="dataTable"></param> 
     /// <param name="fileName">The full file name including the extension.</param> 
     public CSVResult(DataTable dataTable, string fileName) 
     { 
      Table = dataTable; 
      FileName = fileName; 
     } 

     public string FileName { get; protected set; } 
     public DataTable Table { get; protected set; } 




     public override void ExecuteResult(ControllerContext context) 
     { 
      StringBuilder csv = new StringBuilder(10 * Table.Rows.Count * Table.Columns.Count); 

      for (int c = 0; c < Table.Columns.Count; c++) 
      { 
       if (c > 0) 
        csv.Append(","); 
       DataColumn dc = Table.Columns[c]; 
       string columnTitleCleaned = CleanCSVString(dc.ColumnName); 
       csv.Append(columnTitleCleaned); 
      } 
      csv.Append(Environment.NewLine); 
      foreach (DataRow dr in Table.Rows) 
      { 
       StringBuilder csvRow = new StringBuilder(); 
       for(int c = 0; c < Table.Columns.Count; c++) 
       { 
        if(c != 0) 
         csvRow.Append(","); 

        object columnValue = dr[c]; 
        if (columnValue == null) 
         csvRow.Append(""); 
        else 
        { 
         string columnStringValue = columnValue.ToString(); 


         string cleanedColumnValue = CleanCSVString(columnStringValue); 

         if (columnValue.GetType() == typeof(string) && !columnStringValue.Contains(",")) 
         { 
          cleanedColumnValue = "=" + cleanedColumnValue; // Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string. 
         } 
         csvRow.Append(cleanedColumnValue); 
        } 
       } 
       csv.AppendLine(csvRow.ToString()); 
      } 

      HttpResponseBase response = context.HttpContext.Response; 
      response.ContentType = "text/csv"; 
      response.AppendHeader("Content-Disposition", "attachment;filename=" + this.FileName); 
      response.Write(csv.ToString()); 
     } 

     protected string CleanCSVString(string input) 
     { 
      string output = "\"" + input.Replace("\"", "\"\"").Replace("\r\n", " ").Replace("\r", " ").Replace("\n", "") + "\""; 
      return output; 
     } 
    } 
} 
+0

Cảm ơn rất nhiều. Giúp tôi với logic của tệp csv và tải xuống từ trình duyệt. – Soader03

6

Một bình luận về câu trả lời của Will, bạn có thể muốn thay thế HttpContext.Current.Response.End(); với HttpContext.Current.ApplicationInstance.CompleteRequest(); Lý do là Response.End() ném một System.Threading.ThreadAbortException. Nó hủy bỏ một sợi chỉ. Nếu bạn có một logger ngoại lệ, nó sẽ được rải rác với ThreadAbortExceptions, mà trong trường hợp này là hành vi mong đợi.

Bằng trực giác, việc gửi tệp CSV tới trình duyệt sẽ không làm tăng ngoại lệ.

Xem ở đây để biết thêm Is Response.End() considered harmful?

21

Dưới đây là một mã nguồn mở lớp CsvExport miễn phí rất đơn giản cho C#. Có một ví dụ ASP.NET MVC ở phía dưới.

https://github.com/jitbit/CsvExport

Nó sẽ chăm sóc về dòng-chia, dấu phẩy, dấu ngoặc kép thoát, MS Excel tương thích ... Chỉ cần thêm một tập tin ngắn .cs để dự án của bạn và bạn tốt để đi.

(tuyên bố từ chối trách nhiệm: Tôi là một trong những người đóng góp)

+6

cá nhân tôi muốn cảm ơn bạn vì chia sẻ của bạn và công việc tuyệt vời này. – LikePod

+0

cảm ơn. Nó dường như được làm việc. – Reza

Các vấn đề liên quan