Czy ktoś mógłby mi powiedzieć, dlaczego poniższy kod nie działa. Dane są zapisywane w pliku csv, jednak dane nie są rozdzielane. To wszystko istnieje w pierwszej komórce każdego wiersza.
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());
Dzięki.
c#
csv
delimited-text
Darren Young
źródło
źródło
Odpowiedzi:
Następująca krótsza wersja otwiera się dobrze w programie Excel, być może problemem był końcowy przecinek
.net = 3,5
.net> = 4.0
I jak zauważył Tim, jeśli korzystasz z .net> = 4, możesz go jeszcze skrócić:
Zgodnie z sugestią Christiana, jeśli chcesz obsługiwać znaki specjalne uciekające w polach, zamień blok pętli na:
I ostatnia sugestia, możesz napisać zawartość csv wiersz po wierszu zamiast całego dokumentu, aby uniknąć posiadania dużego dokumentu w pamięci.
źródło
ItemArray
do nowegoString[]
, możesz pominąć.ToArray()
.NET 4 i użyćString.Join
przeciążenia, które zajmujeIEnumerable<T>
(edytowane). 
jest typowa dla dokumentów HTML / XML. To nie powyższy kod go tworzy, chyba że tabela
wyraźnie zawieraZawarłem to w klasie rozszerzenia, która umożliwia wywołanie:
na dowolnym DataTable.
źródło
Nowa funkcja rozszerzenia oparta na odpowiedzi Paula Grimshawa. Wyczyściłem to i dodałem możliwość obsługi nieoczekiwanych danych. (Puste dane, osadzone cytaty i przecinki w nagłówkach ...)
Zwraca również łańcuch, który jest bardziej elastyczny. Zwraca Null, jeśli obiekt tabeli nie zawiera żadnej struktury.
Nazywasz to następująco:
źródło
Jeśli kod wywołujący odwołuje się do
System.Windows.Forms
zestawu, możesz rozważyć radykalnie inne podejście. Moja strategia polega na użyciu funkcji już dostarczonych przez framework, aby osiągnąć to w bardzo niewielu wierszach kodu i bez konieczności przechodzenia przez kolumny i wiersze. Poniższy kod programowo tworzy plikDataGridView
w locie i ustawiaDataGridView.DataSource
go naDataTable
. Następnie programowo zaznaczam wszystkie komórki (w tym nagłówek) wDataGridView
i wywołujęDataGridView.GetClipboardContent()
, umieszczając wyniki w systemie WindowsClipboard
. Następnie „wklejam” zawartość schowka do wywołaniaFile.WriteAllText()
, upewniając się, że określam formatowanie „wklej” jakoTextDataFormat.CommaSeparatedValue
.Oto kod:
Zauważ, że zachowuję również zawartość schowka przed rozpoczęciem i przywracam go, gdy skończę, aby użytkownik nie dostał wielu nieoczekiwanych śmieci przy następnej próbie wklejenia. Główne zastrzeżenia dotyczące tego podejścia to 1) Twoja klasa musi się odwoływać
System.Windows.Forms
, co może nie mieć miejsca w warstwie abstrakcji danych, 2) Twój zestaw będzie musiał być przeznaczony dla platformy .NET 4.5, ponieważ DataGridView nie istnieje w 4.0, i 3) Metoda nie powiedzie się, jeśli schowek jest używany przez inny proces.W każdym razie to podejście może nie być odpowiednie w twojej sytuacji, ale jest mimo wszystko interesujące i może być kolejnym narzędziem w twoim zestawie narzędzi.
źródło
.GetClipboardContent
obsługuje również kilka skrajnych przypadków wartości, które zawierają,
."
,\t
(konwertuje tabulator na spację)Zrobiłem to niedawno, ale dodałem podwójne cudzysłowy wokół moich wartości.
Na przykład zmień te dwie linie:
źródło
Spróbuj zmienić
sb.Append(Environment.NewLine);
nasb.AppendLine();
.źródło
Spróbuj
;
zamiast tego,
Mam nadzieję, że to pomoże
źródło
Przeczytaj to i to ?
Lepsza byłaby implementacja
źródło
Błąd jest separatorem listy.
Zamiast pisać
sb.Append(something... + ',')
powinieneś wpisać coś w rodzajusb.Append(something... + System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator);
Musisz umieścić znak separatora listy skonfigurowany w systemie operacyjnym (jak w powyższym przykładzie) lub separator listy na komputerze klienta, na którym plik ma być obserwowany. Inną opcją byłoby skonfigurowanie go w pliku app.config lub web.config jako parametr swojej aplikacji.
źródło
4 linie kodu:
Zauważ, że
ToList()
koniec jest ważny; Potrzebuję czegoś, co wymusi ocenę wyrażenia. Gdybym grał w golfa kodowego, przydałbym sięMin()
zamiast tego.Zauważ również, że wynik będzie miał na końcu znak nowej linii z powodu ostatniego wywołania do
AppendLine()
. Możesz tego nie chcieć. Możesz po prostu zadzwonić,TrimEnd()
aby go usunąć.źródło
Oto ulepszenie posta vc-74, które obsługuje przecinki w taki sam sposób, jak Excel. Program Excel umieszcza dane w cudzysłowach, jeśli dane zawierają przecinek, ale nie cytuje, jeśli dane nie zawierają przecinka.
źródło
Aby napisać do pliku, myślę, że następująca metoda jest najbardziej wydajna i prosta: (Jeśli chcesz, możesz dodać cudzysłowy)
źródło
Aby naśladować plik Excel CSV:
źródło
źródło
źródło
Prawdopodobnie najłatwiejszym sposobem będzie użycie:
https://github.com/ukushu/DataExporter
szczególnie w przypadku danych datatable zawierających
/r/n
znaki lub symbol separatora wewnątrz komórek dataTable.Prawie wszystkie inne odpowiedzi nie będą działać z takimi komórkami.wystarczy napisać następujący kod:
źródło
Na wypadek, gdyby ktoś się na to natknął, użyłem File.ReadAllText do uzyskania danych CSV, a następnie zmodyfikowałem je i zapisałem z powrotem za pomocą File.WriteAllText . \ R \ n CRLF były w porządku, ale karty \ t zostały zignorowane, gdy Excel je otworzył. (Wszystkie dotychczasowe rozwiązania w tym wątku używają separatora przecinków, ale to nie ma znaczenia). Notatnik pokazywał ten sam format w pliku wynikowym, co w źródle. A Diff pokazał nawet, że pliki są identyczne. Ale dostałem wskazówkę, kiedy otworzyłem plik w programie Visual Studio za pomocą edytora binarnego. Plik źródłowy był w formacie Unicode, ale celem był ASCII . Aby to naprawić, zmodyfikowałem zarówno ReadAllText, jak i WriteAllText z trzecim argumentem ustawionym jako System.Text.Encoding.Unicode i stamtąd Excel mógł otworzyć zaktualizowany plik.
źródło
FYR
źródło
Oto moje rozwiązanie, oparte na wcześniejszych odpowiedziach Paula Grimshawa i Anthony'ego VO . Wysłałem kod w projekcie C # na Github .
Moim głównym wkładem jest wyeliminowanie jawnego tworzenia i manipulowania
StringBuilder
a zamiast pracy tylko zIEnumerable
. Pozwala to uniknąć alokacji dużego bufora w pamięci.}
To podejście ładnie łączy się z konwersją
IEnumerable
do DataTable, zgodnie z pytaniem tutaj .źródło
Musiałem też nadpisać dane, dlatego jest kilka stwierdzeń „jeśli jeszcze”. Musiałem się upewnić, że jeśli pole jest puste, aby zamiast tego wprowadzić „N / A”, lub jeśli pole daty zostało sformatowane jako „01/01/1900: 00”, zostanie zapisane jako „01/01/1900” zamiast.
źródło
źródło
jeśli wszystkie dane nadal znajdują się w pierwszej komórce, oznacza to, że aplikacja, w której otworzyłeś plik, oczekuje na inny separator. MSExcel może traktować przecinek jako separator, chyba że określono inaczej.
źródło