2010-08-20 19 views
7

W porządku Chcę utworzyć plik .csv w języku C#. Rozglądałem się i zauważyłem, że wiele osób korzysta z system.IO.memorystream i system.io.streamwriter.Utwórz plik .csv w języku C#

Problem polega na tym, że mam aplikację internetową. Chcę dać użytkownikowi możliwość eksportu do programu Excel. Problem polega na tym, że programu Excel nie można zainstalować na serwerze (nie pytaj). Chcę móc eksportować eksport arkusza .csv do raportu. Teraz nagłówki raportów i dane będą inne dla wszystkich raportów (przejście przez to rozwiąże). Czy ktoś ma lepszy przykład lub lepsze zasoby, aby przejść przez to?

+0

Po lekturze. Wszystko, co naprawdę muszę zrobić, to przejrzeć dane wyjściowe i oddzielić je przecinkami z/n na końcu wiersza i przechodzić dalej aż do zrobienia ... zapisać plik jako .csv, a następnie zamknąć strumień ... poprawny? – Tom

+0

Musisz również ustawić typ zawartości, a jeśli baza danych może zawierać znak "", ',' lub znak nowej linii, musisz również uciec. Kod dla tego w mojej odpowiedzi –

Odpowiedz

13

To podejście zwykle biorę. Prawdopodobnie nie jest to najbardziej wydajne.

 /// <summary> 
    /// Generates the contents of the log file. 
    /// </summary> 
    /// <returns>The contents of the log file.</returns> 
    internal string GenerateLogFile() 
    { 
     StringBuilder csvExport = new StringBuilder(); 
     csvExport.AppendLine(Resources.CSVHeader); 

     foreach (DataRow row in this.logEntries.Rows) 
     { 
      csvExport.AppendLine(
       string.Format(
       "\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\", \"{9}\"", 
       row[ColumnNames.LogTime], row[ColumnNames.Field1], row[ColumnNames.Field2], row[ColumnNames.Field3], row[ColumnNames.Field4], row[ColumnNames.Field5], row[ColumnNames.Field6], row[ColumnNames.Field7], row[ColumnNames.Field8], row[ColumnNames.Field9])); 
     } 

     return csvExport.ToString(); 
    } 

    /// <summary> 
    /// Adds the CSV file to the response. 
    /// </summary> 
    /// <param name="csvExportContents">The contents of the CSV file.</param> 
    internal void DisplayLogFile(string csvExportContents) 
    { 
     byte[] data = new ASCIIEncoding().GetBytes(csvExportContents); 

     HttpContext.Current.Response.Clear(); 
     HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM"; 
     HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=Export.csv"); 
     HttpContext.Current.Response.OutputStream.Write(data, 0, data.Length); 
     HttpContext.Current.Response.End(); 
    } 
+1

Skąd pochodzi CSVHeader? – RealityDysfunction

+0

Nie widzę, w jaki sposób wartości, które mogą zawierać '' ', zostaną usunięte. –

+0

@RealityDysfunction Zakładam, że jest z pliku Resx. Byłoby bardziej użyteczne dla przykładu, aby mieć literał łańcuchowy. – MrBoJangles

4

Powinieneś być w stanie korzystać z przykładów z użyciem System.IO.MemoryStream i System.IO.StreamWriter dobrze.

Zamiast zapisywać plik MemoryStream do pliku, można go zwrócić jako strumień odpowiedzi w środowisku ASP.NET (upewniając się, że ustawiono odpowiednie wartości nagłówków, aby przeglądarka wiedziała, że ​​pobiera plik).

3

Naprawdę nie ma magii podczas tworzenia pliku CSV. Jedyny problem z plikami CSV polega na tym, że tak naprawdę nie ma standardu, a większość importerów po prostu zaimplementuje jedno szczególne zachowanie dla procesu importowania. Jeśli masz szczęście, dostaniesz coś, co można stosunkowo dobrze odgadnąć.

Generowanie pliku CSV jest tylko kwestią drukowania linii. Co do rzeczywistych informacji, zapoznaj się z:

http://en.wikipedia.org/wiki/Comma-separated_values

W takiej sytuacji, jeśli to, co chcesz, aby wyeksportować do programu Excel, można użyć Microsoft OOXML SDK:

http://msdn.microsoft.com/en-us/library/bb448854.aspx

OOXML SDK to biblioteka C#, której można użyć do generowania plików Excel na serwerze. Brian Jones blog jest doskonałym źródłem informacji na temat korzystania z tej biblioteki:

http://blogs.msdn.com/b/brian_jones/

+0

Czy do tego potrzebuję programu Excel na serwerze? – Tom

+0

Nie potrzebujesz programu Excel na serwerze, aby uruchomić pakiet OOXML SDK. W rzeczywistości można nawet uruchomić go w systemie Linux z Mono. –

4

Excel jest wymagane tylko w przypadku korzystania z pakietu Office Interop. Używając StringWriter, po prostu utworzysz plik i dodasz informacje o odpowiedzi. Program Excel jest wymagany tylko podczas otwierania pliku.

3

Jeśli nie masz nic przeciwko korzystaniu z biblioteki innej firmy, a licencja LGPL jest w porządku w Twoim projekcie, to FileHelpers jest doskonałym narzędziem do tego.

+1

Uwielbiam FileHelpers! Ta prosta i szybka biblioteka ułatwia przekształcanie płaskich plików w obiekty. Może także przekształcać obiekty w płaskie pliki tekstowe w sposób zorientowany obiektowo. I jest szybki. I ma czarodzieja, który pomoże ci prowadzić. Twoje zdrowie! –

10
private void WriteItem<T>(StreamWriter sr, T item) 
{ 
    string itemString = item.ToString(); 
    if(itemString.IndexOfAny(new char[] { '"', ',', '\n', '\r' }) != -1)//skip test and always escape for different speed/filesize optimisation 
    { 
     sr.Write('"'); 
     sr.Write(itemString.Replace("\"", "\"\"")); 
     sr.Write('"'); 
    } 
    else 
     sr.Write(itemString); 
} 
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line) 
{ 
    bool first = true; 
    foreach(T item in line) 
    { 
     if(!first) 
      sr.Write(','); 
     first = false; 
     WriteItem(sr, item); 
    } 
} 
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines) 
{ 
    bool first = true; 
    foreach(IEnumerable<T> line in allLines) 
    { 
     if(!first) 
      sr.Write('\n'); 
     first = false; 
     WriteLine(sr, line); 
    } 
} 
private void WriteCSV<T>(HttpResponse response, IEnumerable<IEnumerable<T>> allLines) 
{ 
    response.ContentType = "text/csv"; 
    WriteCSV(response.Output, allLines); 
} 

Warto również wysłać nagłówek treści z rekomendowaną nazwą pliku.

Edycja: Ostatnio, w przypadkach, w których trzeba przeplatać akcję między elementami w wyliczeniu (jak przecinek i znak nowej linii powyżej), wolałbym raczej zachować wartość boolowską, która jest ciągle sprawdzana, obsługuję moduł wyliczający bezpośrednio, a następnie obsłużyć pierwszy element oddzielony od reszty. Zacząłem robić to jako mikro-opt w pchnięciu efektywności, ale urosłem, aby znaleźć lepszy wyraz ścieżki kodu, która różni się dla pierwszego przedmiotu.Jako takie, bym teraz napisać jak wyżej:

private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line) 
{ 
    using(var en = line.GetEnumerator()) 
    if(en.MoveNext()) 
    { 
    WriteItem(sr, en.Current); 
    while(en.MoveNext()) 
    { 
     sr.Write(','); 
     WriteItem(sr, en.Current); 
    } 
} 
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines) 
{ 
    using(var en = allLines.GetEnumerator()) 
    if(en.MoveNext()) 
    { 
     WriteLine(sr, en.Current); 
     while(en.MoveNext()) 
     { 
     sr.Write('\n'); 
     WriteLine(sr, en.Current); 
     } 
    } 
} 
2

Ta funkcja służy do tworzenia pliku csv:

private async Task<string> WriteCSV<ViewModel>(IEnumerable<ViewModel> viewModels, string path) 
      { 
       Type itemType = typeof(ViewModel); 
       var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
            .OrderBy(p => p.Name); 

       var blobName = string.Empty; 

       using (var ms = new MemoryStream()) 
       { 

        using (var writer = new System.IO.StreamWriter(ms)) 
        { 
         writer.WriteLine(string.Join(", ", props.Select(p => p.Name))); 

         foreach (var item in viewModels) 
         { 

          writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null)))); 
         } 
    } 

} 
    } 

przeciwnym razie można odnieść poniżej linkiem:

https://travelcodingnlotsmore.wordpress.com/2013/06/06/creating-csv-file-from-data-in-list-object-in-c/