CSV Excel 파일 C #을 만드는 방법은 무엇입니까? [닫은]


132

CSV Excel 파일을 만들기위한 클래스를 찾고 있습니다.

예상되는 기능 :

  • 사용하기 매우 간단
  • 쉼표와 따옴표를 이스케이프 처리하여 Excel에서 잘 처리합니다.
  • 날짜 및 날짜 / 시간을 표준 시간대 형식으로 내 보냅니다.

이것을 할 수있는 수업이 있습니까?


12
QUESTION 부분에 질문을 제기하고 답변 부분에 자신의 답변을 게시하는 것이 좋습니다. 질문에 태그와 키워드를 추가하여 검색 할 수있게하십시오.
Cheeso

중요 : "값"에 캐리지 리턴이있을 때 따옴표를 추가해야합니다.
Alex

감사합니다 @Chris, 내가 제안한다면,이 코드는 KeyNotFoundException을 던질 수 있습니다. 제 답변을 참조하십시오.
Joseph

가장 좋은 예 ...하지만 어떻게 단일 파일에 두 개의 테이블을 추가 할 수 있습니까, 두 개의 행으로 구성된 하나의 테이블이 있고 다른 테이블은 10 개의 행이며 고유 한 열 이름이 있음을 의미합니다. 두 줄의 간격 나는 두 번째 테이블을 추가하고 싶습니다.
Floki

답변:


92

약간의 다른 버전으로 내 요구에 반영을 사용하여 썼습니다. 객체 목록을 csv로 내 보내야했습니다. 누군가가 나중에 그것을 사용하기를 원할 경우.

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;

        }
    }

사용 샘플 : (주석마다 업데이트)

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

5
더 비슷했습니다 : List <BusinessObject> x = new List <BusinessObject> (); CsvExport <BusinessObject> x = 새 CsvExport <BusinessObject> (MUsers);
숨겨진

5
INullable 인터페이스는 어디에서 왔습니까?
Kilhoffer

가장 좋은 예 ...하지만 어떻게 단일 파일에 두 개의 테이블을 추가 할 수 있습니까, 두 개의 행으로 구성된 하나의 테이블이 있고 다른 테이블은 10 개의 행이며 고유 한 열 이름이 있음을 의미합니다. 두 줄의 간격 나는 두 번째 테이블을 추가하고 싶습니다.
Floki

2
원래 게시물이 2011 년에 나온 것임을 알고 있으므로 당시에 사용 된 .NET 버전에서 가능했는지 확실하지 않습니다. 그러나 public string Export()메소드를 제거하고 다른 메소드를 public string Export(bool includeHeaderLiner = true)(기본 매개 변수 값으로) 변경 하지 않는 이유는 무엇입니까? 다시 말하지만 2011 년에 기본 매개 변수를 사용할 수 있는지 확실하지 않지만 현재 코드는 정통적으로 보입니다.
Kevin Cruijssen

19

용서 해주세요

그러나 공개 오픈 소스 저장소는 코드를 공유하고 공헌하고 수정하고 "이 문제를 해결했습니다.

그래서 주제 시작 코드와 모든 추가 사항으로 간단한 git-repository를 만들었습니다.

https://github.com/jitbit/CsvExport

또한 몇 가지 유용한 수정 사항을 직접 추가했습니다. 누구나 제안을 추가하고, 포크 등을 공헌 할 수 있습니다. 포크를 보내서 리포지토리에 다시 병합하십시오.

추신. Chris에 대한 모든 저작권 표시를 게시했습니다. @Chris이 아이디어에 반대하는 경우 알려주세요.


11

CSV 파일을 읽고 쓰는 또 다른 좋은 솔루션은 파일 도우미 (오픈 소스)입니다.


주의 : Excel 지원은 기본 시나리오에만 해당됩니다 . 현재 구현 된 Excel 지원은 기본 시나리오에만 해당됩니다. 사용자 정의 형식, 차트 등이 필요한 경우 사용자 정의 코드를 사용해야합니다. NPOI 라이브러리를 직접 사용하는 것이 좋습니다.
AK

6

모든 foreach 루프 대신 string.Join을 사용하는 것은 어떻습니까?


String.Join은 string []에서만 작동하는 반면 List <string>의 일부 기능을 사용하고 있습니다.
Chris

12
String.Join("," , List<string>)또한 작동합니다.
Dementic

6

누구든지 IEnumerable의 확장 메소드로 변환하고 싶다면 :

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

이 수업에 큰 도움이됩니다. 간단하고 사용하기 쉽습니다. 내보내기의 첫 번째 행에 제목을 포함하도록 클래스를 수정했습니다. 내가 공유 할 것이라고 생각했다.

사용하다:

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

수업:

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

csv가 먼저 하드 드라이브에 저장할 필요가 없도록 ExportToStream을 추가했습니다.

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

3

추가했습니다

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);

}

이전 코드는 이전 .NET 버전에서 작동하지 않습니다. 3.5 버전의 프레임 워크에는이 다른 버전을 사용하십시오.

        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

고마워요! 클래스를 다음과 같이 수정했습니다.

  • 코드에 하드 코딩 된 대신 변수 구분 기호를 사용하십시오.
  • 모든 줄 바꾸기 (\ n \ r \ n \ r)를 MakeValueCsvFriendly

암호:

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

원래 클래스에 문제가 있으므로 새 열을 추가하려는 경우 Export 메서드에서 KeyNotFoundException이 발생합니다. 예를 들면 다음과 같습니다.

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");
}

이를 해결하고 리플렉션을 사용하는 @KeyboardCowboy 아이디어를 사용하기 위해 동일한 열이없는 행을 추가 할 수 있도록 코드를 수정했습니다. 익명 클래스의 인스턴스를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

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");
}

CsvExporter 에서 소스 코드를 다운로드 할 수 있습니다 . 자유롭게 사용하고 수정하십시오.

이제 작성하려는 모든 행이 동일한 클래스 인 경우 성능 향상 RAM 사용률이 높고 대용량 파일을 작성하는 데 이상적인 일반 클래스 CsvWriter.cs를 만들었습니다. 또한 원하는 데이터 형식에 포맷터를 추가 할 수 있습니다 . 사용 예 :

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

이를 위해서는 하나의 기능 만 필요합니다. 솔루션 탐색기에서 폴더를 만들어 csv 파일을 저장 한 다음 해당 파일을 사용자에게 내 보내면됩니다.

필자의 경우 폴더 다운로드가 있습니다. 먼저 모든 내용을 해당 디렉토리로 내 보낸 다음 사용자에게 내 보냅니다. response.end 처리를 위해 ThreadAbortException을 사용했습니다. 그래서 그것은 내 솔루션에서 100 % 정품이며 작동하는 기능입니다.

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....
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.