[c#] csv에 c # 데이터 테이블

누군가 다음 코드가 작동하지 않는 이유를 알려주십시오. 데이터는 csv 파일에 저장되지만 데이터는 분리되지 않습니다. 그것은 모두 각 행의 첫 번째 셀 내에 존재합니다.

StringBuilder sb = new StringBuilder();

foreach (DataColumn col in dt.Columns)
{
    sb.Append(col.ColumnName + ',');
}

sb.Remove(sb.Length - 1, 1);
sb.Append(Environment.NewLine);

foreach (DataRow row in dt.Rows)
{
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        sb.Append(row[i].ToString() + ",");
    }

    sb.Append(Environment.NewLine);
}

File.WriteAllText("test.csv", sb.ToString());

감사.



답변

다음의 짧은 버전은 Excel에서 잘 열립니다. 문제는 후행 쉼표 일 수 있습니다.

.net = 3.5

StringBuilder sb = new StringBuilder();

string[] columnNames = dt.Columns.Cast<DataColumn>().
                                  Select(column => column.ColumnName).
                                  ToArray();
sb.AppendLine(string.Join(",", columnNames));

foreach (DataRow row in dt.Rows)
{
    string[] fields = row.ItemArray.Select(field => field.ToString()).
                                    ToArray();
    sb.AppendLine(string.Join(",", fields));
}

File.WriteAllText("test.csv", sb.ToString());

.net> = 4.0

Tim이 지적했듯이 .net> = 4에 있으면 더 짧게 만들 수 있습니다.

StringBuilder sb = new StringBuilder();

IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().
                                  Select(column => column.ColumnName);
sb.AppendLine(string.Join(",", columnNames));

foreach (DataRow row in dt.Rows)
{
    IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
    sb.AppendLine(string.Join(",", fields));
}

File.WriteAllText("test.csv", sb.ToString());

Christian이 제안한대로 필드에서 이스케이프되는 특수 문자를 처리하려면 루프 블록을 다음과 같이 바꾸십시오.

foreach (DataRow row in dt.Rows)
{
    IEnumerable<string> fields = row.ItemArray.Select(field =>
      string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\""));
    sb.AppendLine(string.Join(",", fields));
}

마지막으로 csv 콘텐츠를 전체 문서가 아닌 한 줄씩 작성하여 메모리에 큰 문서가 생기지 않도록 할 수 있습니다.


답변

이것을 확장 클래스로 묶어 다음을 호출 할 수 있습니다.

myDataTable.WriteToCsvFile("C:\\MyDataTable.csv");

모든 DataTable에서.

public static class DataTableExtensions
{
    public static void WriteToCsvFile(this DataTable dataTable, string filePath)
    {
        StringBuilder fileContent = new StringBuilder();

        foreach (var col in dataTable.Columns)
        {
            fileContent.Append(col.ToString() + ",");
        }

        fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1);

        foreach (DataRow dr in dataTable.Rows)
        {
            foreach (var column in dr.ItemArray)
            {
                fileContent.Append("\"" + column.ToString() + "\",");
            }

            fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1);
        }

        System.IO.File.WriteAllText(filePath, fileContent.ToString());
    }
}


답변

Paul Grimshaw의 답변을 기반으로 한 새로운 확장 기능. 나는 그것을 정리하고 예기치 않은 데이터를 처리하는 기능을 추가했습니다. (헤딩에 빈 데이터, 포함 된 따옴표 및 쉼표 …)

또한 더 유연한 문자열을 반환합니다. 테이블 개체에 구조가 포함되어 있지 않으면 Null을 반환합니다.

    public static string ToCsv(this DataTable dataTable) {
        StringBuilder sbData = new StringBuilder();

        // Only return Null if there is no structure.
        if (dataTable.Columns.Count == 0)
            return null;

        foreach (var col in dataTable.Columns) {
            if (col == null)
                sbData.Append(",");
            else
                sbData.Append("\"" + col.ToString().Replace("\"", "\"\"") + "\",");
        }

        sbData.Replace(",", System.Environment.NewLine, sbData.Length - 1, 1);

        foreach (DataRow dr in dataTable.Rows) {
            foreach (var column in dr.ItemArray) {
                if (column == null)
                    sbData.Append(",");
                else
                    sbData.Append("\"" + column.ToString().Replace("\"", "\"\"") + "\",");
            }
            sbData.Replace(",", System.Environment.NewLine, sbData.Length - 1, 1);
        }

        return sbData.ToString();
    }

다음과 같이 호출합니다.

var csvData = dataTableOject.ToCsv();


답변

호출 코드가 System.Windows.Forms어셈블리를 참조하는 경우 근본적으로 다른 접근 방식을 고려할 수 있습니다. 내 전략은 프레임 워크에서 이미 제공하는 함수를 사용하여 열과 행을 반복 할 필요없이 매우 적은 코드 줄로이를 수행하는 것입니다. 아래 코드가하는 일은 프로그래밍 방식으로 DataGridView즉석에서 DataGridView.DataSource를 만들고 DataTable. 다음으로, DataGridView및 호출의 모든 셀 (헤더 포함)을 프로그래밍 방식으로 선택 DataGridView.GetClipboardContent()하고 결과를 Windows에 배치합니다 Clipboard. 그런 다음 클립 보드의 내용을에 대한 호출에 File.WriteAllText()‘붙여 넣기’하여 ‘붙여 넣기’의 형식을 TextDataFormat.CommaSeparatedValue.

다음은 코드입니다.

public static void DataTableToCSV(DataTable Table, string Filename)
{
    using(DataGridView dataGrid = new DataGridView())
    {
        // Save the current state of the clipboard so we can restore it after we are done
        IDataObject objectSave = Clipboard.GetDataObject();

        // Set the DataSource
        dataGrid.DataSource = Table;
        // Choose whether to write header. Use EnableWithoutHeaderText instead to omit header.
        dataGrid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
        // Select all the cells
        dataGrid.SelectAll();
        // Copy (set clipboard)
        Clipboard.SetDataObject(dataGrid.GetClipboardContent());
        // Paste (get the clipboard and serialize it to a file)
        File.WriteAllText(Filename,Clipboard.GetText(TextDataFormat.CommaSeparatedValue));

        // Restore the current state of the clipboard so the effect is seamless
        if(objectSave != null) // If we try to set the Clipboard to an object that is null, it will throw...
        {
            Clipboard.SetDataObject(objectSave);
        }
    }
}

또한 시작하기 전에 클립 보드의 내용을 보존하고 완료되면 복원하여 다음에 사용자가 붙여 넣으려고 할 때 예상치 못한 쓰레기가 발생하지 않도록합니다. 이 접근 방식에 대한 주요주의 사항은 1) 클래스가를 참조 System.Windows.Forms해야한다는 것입니다. 데이터 추상화 계층에서는 그렇지 않을 수 있습니다. 2) DataGridView가 4.0에 존재하지 않기 때문에 어셈블리가 .NET 4.5 프레임 워크를 대상으로해야합니다. 3) 다른 프로세스에서 클립 보드를 사용중인 경우 메서드가 실패합니다.

어쨌든,이 접근 방식은 귀하의 상황에 적합하지 않을 수 있지만 그다지 흥미롭지 않으며 도구 상자의 또 다른 도구가 될 수 있습니다.


답변

나는 최근에 이것을했지만 내 가치 주위에 큰 따옴표를 포함했습니다.

예를 들어 다음 두 줄을 변경합니다.

sb.Append("\"" + col.ColumnName + "\",");
...
sb.Append("\"" + row[i].ToString() + "\","); 


답변

변경 시도 sb.Append(Environment.NewLine);sb.AppendLine();.

StringBuilder sb = new StringBuilder();
foreach (DataColumn col in dt.Columns)
{
    sb.Append(col.ColumnName + ',');
}

sb.Remove(sb.Length - 1, 1);
sb.AppendLine();

foreach (DataRow row in dt.Rows)
{
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        sb.Append(row[i].ToString() + ",");
    }

    sb.AppendLine();
}

File.WriteAllText("test.csv", sb.ToString());


답변

;대신 넣어보십시오,

도움이되기를 바랍니다.