CSV Excel dosyası C # nasıl oluşturulur? [kapalı]


132

CSV Excel dosyaları oluşturmak için bir sınıf arıyorum.

Beklenen özellikler:

  • Kullanımı son derece basit
  • Virgül ve tırnak işaretlerinden kaçar, böylece excel bunları iyi yönetir
  • Tarih ve veri saatlerini saat dilimine dayanıklı biçimde dışa aktarır

Bunu yapabilen herhangi bir sınıf biliyor musunuz?


12
soruyu SORU bölümünde sormak ve ardından kendi cevabınızı CEVAP bölümüne göndermek daha iyidir. Soruyu aranabilir hale getirmek için soruya etiketler ve anahtar kelimeler eklediğinizden emin olun.
Cheeso

ÖNEMLİ: "değer" bölümünde TAŞIMA İADESİ olduğunda da fiyat teklifi eklemelisiniz.
Alex

Teşekkürler @Chris, bir öneri, eğer yapabilirsem, bu kod bir KeyNotFoundException oluşturabilir, lütfen cevabıma bakın.
Joseph

En iyi örneği ... ama tek dosyada iki tabloyu nasıl ekleyebilirim, iki satırlık bir tabloya sahip olduğum ve diğer tablonun 10 satır olduğu ve her ikisinin de benzersiz sütun adına sahip olduğu anlamına gelir. iki satırlık boşluk ikinci tablo eklemek istiyorum.
Floki

Yanıtlar:


92

İhtiyaçlarım için yansıma kullanarak yazdığım biraz farklı bir versiyon. Nesnelerin bir listesini csv'ye aktarmak zorunda kaldım. Birisi onu gelecekte kullanmak isterse diye.

public class CsvExport<T> where T: class
    {
        public List<T> Objects;

        public CsvExport(List<T> objects)
        {
            Objects = objects;
        }

        public string Export()
        {
            return Export(true);
        }

        public string Export(bool includeHeaderLine)
        {

            StringBuilder sb = new StringBuilder();
            //Get properties using reflection.
            IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();

            if (includeHeaderLine)
            {
                //add header line.
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    sb.Append(propertyInfo.Name).Append(",");
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            //add value for each property.
            foreach (T obj in Objects)
            {               
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    sb.Append(MakeValueCsvFriendly(propertyInfo.GetValue(obj, null))).Append(",");
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            return sb.ToString();
        }

        //export to a file.
        public void ExportToFile(string path)
        {
            File.WriteAllText(path, Export());
        }

        //export as binary data.
        public byte[] ExportToBytes()
        {
            return Encoding.UTF8.GetBytes(Export());
        }

        //get the csv value for field.
        private string MakeValueCsvFriendly(object value)
        {
            if (value == null) return "";
            if (value is Nullable && ((INullable)value).IsNull) return "";

            if (value is DateTime)
            {
                if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                    return ((DateTime)value).ToString("yyyy-MM-dd");
                return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
            }
            string output = value.ToString();

            if (output.Contains(",") || output.Contains("\""))
                output = '"' + output.Replace("\"", "\"\"") + '"';

            return output;

        }
    }

Kullanım örneği: (yorum başına güncellenir)

CsvExport<BusinessObject> csv= new CsvExport<BusinessObject>(GetBusinessObjectList());
Response.Write(csv.Export());

5
Daha çok şuna benziyordu: List <BusinessObject> x = new List <BusinessObject> (); CsvExport <BusinessObject> x = new CsvExport <BusinessObject> (MUsers);
gizlendi

5
INullable arayüzünüz nereden geldi?
Kilhoffer

En iyi örneği ... ama tek dosyada iki tabloyu nasıl ekleyebilirim, iki satırlık bir tabloya sahip olduğum ve diğer tablonun 10 satır olduğu ve her ikisinin de benzersiz sütun adına sahip olduğu anlamına gelir. iki satırlık boşluk ikinci tablo eklemek istiyorum.
Floki

2
Orijinal gönderinin 2011 yılına ait olduğunu biliyorum, bu yüzden o zamanlar kullanılan .NET sürümünde bunun mümkün olup olmadığından emin değilim. Ama neden public string Export()yöntemi kaldırıp diğer yöntemi public string Export(bool includeHeaderLiner = true)(varsayılan parametre değeriyle) olarak değiştirmiyorsunuz? Yine, varsayılan parametrelerin 2011'de mevcut olup olmadığından emin değilim, ancak mevcut kod bana sadece alışılmışın dışında görünüyor.
Kevin Cruijssen

19

beni Affet lütfen

Ancak, herkese açık bir açık kaynak havuzunun kodu paylaşmanın, katkı sağlamanın ve düzeltmelerin ve "Bunu düzelttim, bunu düzelttim" gibi eklemelerin daha iyi bir yolu olduğunu düşünüyorum.

Bu yüzden konu başlatıcının kodundan ve tüm eklemelerden basit bir git deposu yaptım:

https://github.com/jitbit/CsvExport

Ayrıca kendime birkaç faydalı düzeltme ekledim. Herkes öneri ekleyebilir, katkıda bulunmak için çatallayabilir vb. Vb. Çatallarınızı bana gönderin, böylece onları depoda birleştireyim.

PS. Chris için tüm telif hakkı bildirimlerini gönderdim. @Chris eğer bu fikre karşıysan - bana haber ver, onu öldüreceğim.


11

CSV dosyalarını okumak ve yazmak için başka bir iyi çözüm dosya yardımcısıdır (açık kaynak).


Not: Excel desteği yalnızca temel senaryolar içindir : Mevcut uygulanan Excel desteği yalnızca temel senaryolar içindir. Özel biçimlendirmeye, çizelgelere vb. İhtiyacınız varsa, özel bir kod seçmelisiniz. Doğrudan NPOI kitaplığını kullanmanız şiddetle tavsiye edilir
AK

6

Tüm foreach döngüleri yerine string.Join kullanmaya ne dersiniz?


String.Join yalnızca string [] üzerinde çalışıyor, oysa List <string> 'in bazı özelliklerini kullanıyorum.
Chris

12
String.Join("," , List<string>)aynı zamanda çalışır.
Dementic

6

Herhangi biri bunu IEnumerable'da bir uzantı yöntemine dönüştürmemi isterse:

public static class ListExtensions
{
    public static string ExportAsCSV<T>(this IEnumerable<T> listToExport, bool includeHeaderLine, string delimeter)
    {
        StringBuilder sb = new StringBuilder();

        IList<PropertyInfo> propertyInfos = typeof(T).GetProperties();

        if (includeHeaderLine)
        {
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                sb.Append(propertyInfo.Name).Append(",");
            }
            sb.Remove(sb.Length - 1, 1).AppendLine();
        }

        foreach (T obj in listToExport)
        {
            T localObject = obj;

            var line = String.Join(delimeter, propertyInfos.Select(x => SanitizeValuesForCSV(x.GetValue(localObject, null), delimeter)));

            sb.AppendLine(line);
        }

        return sb.ToString();
    }

    private static string SanitizeValuesForCSV(object value, string delimeter)
    {
        string output;

        if (value == null) return "";

        if (value is DateTime)
        {
            output = ((DateTime)value).ToLongDateString();
        }
        else
        {
            output = value.ToString();                
        }

        if (output.Contains(delimeter) || output.Contains("\""))
            output = '"' + output.Replace("\"", "\"\"") + '"';

        output = output.Replace("\n", " ");
        output = output.Replace("\r", "");

        return output;
    }
}

5

Bu sınıfta harika iş çıkardınız. Basit ve kullanımı kolay. Dışa aktarmanın ilk satırına bir başlık eklemek için sınıfı değiştirdim; paylaşacağımı düşündüm:

kullanın:

CsvExport myExport = new CsvExport();
myExport.addTitle = String.Format("Name: {0},{1}", lastName, firstName));

sınıf:

public class CsvExport
{
    List<string> fields = new List<string>();

    public string addTitle { get; set; } // string for the first row of the export

    List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
    Dictionary<string, object> currentRow
    {
        get
        {
            return rows[rows.Count - 1];
        }
    }

    public object this[string field]
    {
        set
        {
            if (!fields.Contains(field)) fields.Add(field);
            currentRow[field] = value;
        }
    }

    public void AddRow()
    {
        rows.Add(new Dictionary<string, object>());
    }

    string MakeValueCsvFriendly(object value)
    {
        if (value == null) return "";
        if (value is Nullable && ((INullable)value).IsNull) return "";
        if (value is DateTime)
        {
            if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                return ((DateTime)value).ToString("yyyy-MM-dd");
            return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
        }
        string output = value.ToString();
        if (output.Contains(",") || output.Contains("\""))
            output = '"' + output.Replace("\"", "\"\"") + '"';
        return output;

    }

    public string Export()
    {
        StringBuilder sb = new StringBuilder();

        // if there is a title
        if (!string.IsNullOrEmpty(addTitle))
        {
            // escape chars that would otherwise break the row / export
            char[] csvTokens = new[] { '\"', ',', '\n', '\r' };

            if (addTitle.IndexOfAny(csvTokens) >= 0)
            {
                addTitle = "\"" + addTitle.Replace("\"", "\"\"") + "\"";
            }
            sb.Append(addTitle).Append(",");
            sb.AppendLine();
        }


        // The header
        foreach (string field in fields)
        sb.Append(field).Append(",");
        sb.AppendLine();

        // The rows
        foreach (Dictionary<string, object> row in rows)
        {
            foreach (string field in fields)
                sb.Append(MakeValueCsvFriendly(row[field])).Append(",");
            sb.AppendLine();
        }

        return sb.ToString();
    }

    public void ExportToFile(string path)
    {
        File.WriteAllText(path, Export());
    }

    public byte[] ExportToBytes()
    {
        return Encoding.UTF8.GetBytes(Export());
    }
}


3

ExportToStream'i ekledim, böylece csv'nin önce sabit sürücüye kaydetmesi gerekmedi.

public Stream ExportToStream()
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(Export(true));
    writer.Flush();
    stream.Position = 0;
    return stream;
}

3

ekledim

public void ExportToFile(string path, DataTable tabela)
{

     DataColumnCollection colunas = tabela.Columns;

     foreach (DataRow linha in tabela.Rows)
     {

           this.AddRow();

           foreach (DataColumn coluna in colunas)

           {

               this[coluna.ColumnName] = linha[coluna];

           }

      }
      this.ExportToFile(path);

}

Önceki kod, eski .NET sürümleriyle çalışmaz. Çerçevenin 3.5 sürümü için bu diğer sürümü kullanın:

        public void ExportToFile(string path)
    {
        bool abort = false;
        bool exists = false;
        do
        {
            exists = File.Exists(path);
            if (!exists)
            {
                if( !Convert.ToBoolean( File.CreateText(path) ) )
                        abort = true;
            }
        } while (!exists || abort);

        if (!abort)
        {
            //File.OpenWrite(path);
            using (StreamWriter w = File.AppendText(path))
            {
                w.WriteLine("hello");
            }

        }

        //File.WriteAllText(path, Export());
    }

2

Bunun için çok teşekkürler! Sınıfı şu şekilde değiştirdim:

  • kodda kodlanmış yerine bir değişken sınırlayıcı kullanın
  • içindeki tüm yeni Satırları (\ n \ r \ n \ r) değiştirme MakeValueCsvFriendly

Kod:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

    public class CsvExport
    {

        public char delim = ';';
        /// <summary>
        /// To keep the ordered list of column names
        /// </summary>
        List<string> fields = new List<string>();

        /// <summary>
        /// The list of rows
        /// </summary>
        List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();

        /// <summary>
        /// The current row
        /// </summary>
        Dictionary<string, object> currentRow { get { return rows[rows.Count - 1]; } }

        /// <summary>
        /// Set a value on this column
        /// </summary>
        public object this[string field]
        {
            set
            {
                // Keep track of the field names, because the dictionary loses the ordering
                if (!fields.Contains(field)) fields.Add(field);
                currentRow[field] = value;
            }
        }

        /// <summary>
        /// Call this before setting any fields on a row
        /// </summary>
        public void AddRow()
        {
            rows.Add(new Dictionary<string, object>());
        }

        /// <summary>
        /// Converts a value to how it should output in a csv file
        /// If it has a comma, it needs surrounding with double quotes
        /// Eg Sydney, Australia -> "Sydney, Australia"
        /// Also if it contains any double quotes ("), then they need to be replaced with quad quotes[sic] ("")
        /// Eg "Dangerous Dan" McGrew -> """Dangerous Dan"" McGrew"
        /// </summary>
        string MakeValueCsvFriendly(object value)
        {
            if (value == null) return "";
            if (value is INullable && ((INullable)value).IsNull) return "";
            if (value is DateTime)
            {
                if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                    return ((DateTime)value).ToString("yyyy-MM-dd");
                return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
            }
            string output = value.ToString();
            if (output.Contains(delim) || output.Contains("\""))
                output = '"' + output.Replace("\"", "\"\"") + '"';
            if (Regex.IsMatch(output,  @"(?:\r\n|\n|\r)"))
                output = string.Join(" ", Regex.Split(output, @"(?:\r\n|\n|\r)"));
            return output;
        }

        /// <summary>
        /// Output all rows as a CSV returning a string
        /// </summary>
        public string Export()
        {
            StringBuilder sb = new StringBuilder();

            // The header
            foreach (string field in fields)
                sb.Append(field).Append(delim);
            sb.AppendLine();

            // The rows
            foreach (Dictionary<string, object> row in rows)
            {
                foreach (string field in fields)
                    sb.Append(MakeValueCsvFriendly(row[field])).Append(delim);
                sb.AppendLine();
            }

            return sb.ToString();
        }

        /// <summary>
        /// Exports to a file
        /// </summary>
        public void ExportToFile(string path)
        {
            File.WriteAllText(path, Export());
        }

        /// <summary>
        /// Exports as raw UTF8 bytes
        /// </summary>
        public byte[] ExportToBytes()
        {
            return Encoding.UTF8.GetBytes(Export());

        }

    }


1

Orijinal sınıfta bir sorun var ve bu, yeni bir sütun eklemek istiyorsanız, Dışa Aktarma yönteminde KeyNotFoundException alacaksınız. Örneğin:

static void Main(string[] args)
{
    var export = new CsvExport();

    export.AddRow();
    export["Region"] = "New York, USA";
    export["Sales"] = 100000;
    export["Date Opened"] = new DateTime(2003, 12, 31);

    export.AddRow();
    export["Region"] = "Sydney \"in\" Australia";
    export["Sales"] = 50000;
    export["Date Opened"] = new DateTime(2005, 1, 1, 9, 30, 0);
    export["Balance"] = 3.45f;  //Exception is throwed for this new column

    export.ExportToFile("Somefile.csv");
}

Bunu çözmek için ve @KeyboardCowboy yansımayı kullanma fikrini kullanarak, aynı sütunlara sahip olmayan satırların eklenmesine izin verecek şekilde kodu değiştirdim. Anonim sınıfların örneklerini kullanabilirsiniz. Örneğin:

static void Main(string[] args)
{
    var export = new CsvExporter();

    export.AddRow(new {A = 12, B = "Empty"});
    export.AddRow(new {A = 34.5f, D = false});

    export.ExportToFile("File.csv");
}

Kaynak kodunu buradan CsvExporter indirebilirsiniz . Kullanmaktan ve değiştirmekten çekinmeyin.

Şimdi, yazmak istediğiniz tüm satırlar aynı sınıftaysa , daha iyi bir RAM kullanımına sahip ve büyük dosyalar yazmak için ideal olan genel CsvWriter.cs sınıfını oluşturdum.Ayrıca istediğiniz veri türüne formatlayıcı eklemenizi sağlar . Bir kullanım örneği:

class Program
{
    static void Main(string[] args)
    {
        var writer = new CsvWriter<Person>("Persons.csv");

        writer.AddFormatter<DateTime>(d => d.ToString("MM/dd/yyyy"));

        writer.WriteHeaders();
        writer.WriteRows(GetPersons());

        writer.Flush();
        writer.Close();
    }

    private static IEnumerable<Person> GetPersons()
    {
        yield return new Person
            {
                FirstName = "Jhon", 
                LastName = "Doe", 
                Sex = 'M'
            };

        yield return new Person
            {
                FirstName = "Jhane", 
                LastName = "Doe",
                Sex = 'F',
                BirthDate = DateTime.Now
            };
        }
    }


    class Person
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public char Sex  { get; set; }

        public DateTime BirthDate { get; set; }
    }

0

Bunu yapmak için sadece 1 işleve ihtiyacınız var. Tek yapmanız gereken, çözüm gezgininizde bir klasör oluşturmak ve csv dosyasını orada depolamak ve ardından bu dosyayı kullanıcıya aktarmaktır.

Benim durumumda olduğu gibi bir klasör yüklemem var. Önce tüm içeriğimi o dizine ve ardından kullanıcıya aktarıyorum. Response.end işleme için ThreadAbortException kullandım. Bu yüzden benim çözümümde% 100 gerçek ve çalışan bir fonksiyon.

protected void lnkExport_OnClick(object sender, EventArgs e)
{

    string filename = strFileName = "Export.csv";

    DataTable dt = obj.GetData();  

// call the content and load it into the datatable

    strFileName = Server.MapPath("Downloads") + "\\" + strFileName;

// creating a file in the downloads folder in your solution explorer

    TextWriter tw = new StreamWriter(strFileName);

// using the built in class textwriter for writing your content in the exporting file

    string strData = "Username,Password,City";

// above line is the header for your exported file. So add headings for your coloumns in excel(.csv) file and seperate them with ","

    strData += Environment.NewLine;

// setting the environment to the new line

    foreach (DataRow dr in dt.Rows)
    {
       strData += dr["Username"].ToString() + "," + dr["Password"].ToString() + "," +      dr["City"].ToString();
       strData += Environment.NewLine;
    }

// everytime when loop execute, it adds a line into the file
    tw.Write(strData);

// writing the contents in file
    tw.Close();

// closing the file
    Response.Redirect("Downloads/" + filename);

// exporting the file to the user as a popup to save as....
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.