Question

I am trying to export data from a list of object to a csv file. I managed to create the file and create the first row, however I need to create some kind of for each loop to loop through each object.

This is my code:

string pathDesktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string filePath = pathDesktop + "\\mycsvfile.csv";

if (!File.Exists(filePath))
{
    File.Create(filePath).Close();
}

string delimter = ",";
string[][] output = new string[][] { 
  new string[] {"TEST1","TEST2"} 
};

int length = output.GetLength(0);
StringBuilder sb = new StringBuilder();

for (int index = 0; index < length; index++)
{
    sb.AppendLine(string.Join(delimter, output[index]));
    File.AppendAllText(filePath, sb.ToString());
}

Is there any way to create this file and using a loop to loop through all my objects and display them in file.

Was it helpful?

Solution

Here's the solution:

string pathDesktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string filePath = pathDesktop + "\\mycsvfile.csv";

if (!File.Exists(filePath))
{
    File.Create(filePath).Close();
}
string delimter = ",";
List<string[]> output = new List<string[]>();

//flexible part ... add as many object as you want based on your app logic
output.Add(new string[] {"TEST1","TEST2"});
output.Add(new string[] {"TEST3","TEST4"});

int length = output.Count;

using (System.IO.TextWriter writer = File.CreateText(filePath))
{
    for (int index = 0; index < length; index++)
    {
        writer.WriteLine(string.Join(delimter, output[index]));
    }
}

OTHER TIPS

Assuming that obj is a List of String I usually use this

System.IO.File.WriteAllLines(stringFilePath, obj.ToArray());

If you want a generic extension that will loop through every item in your list adding it to a new line and loop through every public property with a getter and create a comma separated list of fields per property on the line you can use my extension as per my tip, here or my Gist, here, calling the extension on the List like so:

MyList.ToDelimitedText(",", true);

Full code below

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Gists.Extensions.ListOfTExtentions
{
    public static class ListOfTExtentions
    {
        /// <summary>
        /// Converst this instance to delimited text.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instance">The instance.</param>
        /// <param name="delimiter">The delimiter.</param>
        /// <param name="trimTrailingNewLineIfExists">
        /// If set to <c>true</c> then trim trailing new line if it exists.
        /// </param>
        /// <returns></returns>
        public static string ToDelimitedText<T>(this List<T> instance, 
            string delimiter, 
            bool trimTrailingNewLineIfExists = false)
            where T : class, new()
        {
            int itemCount = instance.Count;
            if (itemCount == 0) return string.Empty;

            var properties = GetPropertiesOfType<T>();
            int propertyCount = properties.Length;
            var outputBuilder = new StringBuilder();

            for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
            {
                T listItem = instance[itemIndex];
                AppendListItemToOutputBuilder(outputBuilder, listItem, properties, propertyCount, delimiter);

                AddNewLineIfRequired(trimTrailingNewLineIfExists, itemIndex, itemCount, outputBuilder);
            }

            var output = TrimTrailingNewLineIfExistsAndRequired(outputBuilder.ToString(), trimTrailingNewLineIfExists);
            return output;
        }

        private static void AddDelimiterIfRequired(StringBuilder outputBuilder, int propertyCount, string delimiter,
            int propertyIndex)
        {
            bool isLastProperty = (propertyIndex + 1 == propertyCount);
            if (!isLastProperty)
            {
                outputBuilder.Append(delimiter);
            }
        }

        private static void AddNewLineIfRequired(bool trimTrailingNewLineIfExists, int itemIndex, int itemCount,
            StringBuilder outputBuilder)
        {
            bool isLastItem = (itemIndex + 1 == itemCount);
            if (!isLastItem || !trimTrailingNewLineIfExists)
            {
                outputBuilder.Append(Environment.NewLine);
            }
        }

        private static void AppendListItemToOutputBuilder<T>(StringBuilder outputBuilder, 
            T listItem, 
            PropertyInfo[] properties,
            int propertyCount,
            string delimiter)
            where T : class, new()
        {

            for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex += 1)
            {
                var property = properties[propertyIndex];
                var propertyValue = property.GetValue(listItem);
                outputBuilder.Append(propertyValue);

                AddDelimiterIfRequired(outputBuilder, propertyCount, delimiter, propertyIndex);
            }
        }

        private static PropertyInfo[] GetPropertiesOfType<T>() where T : class, new()
        {
            Type itemType = typeof (T);
            var properties = itemType.GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public);
            return properties;
        }

        private static string TrimTrailingNewLineIfExistsAndRequired(string output, bool trimTrailingNewLineIfExists)
        {
            if (!trimTrailingNewLineIfExists || !output.EndsWith(Environment.NewLine)) return output;

            int outputLength = output.Length;
            int newLineLength = Environment.NewLine.Length;
            int startIndex = outputLength - newLineLength;
            output = output.Substring(startIndex, newLineLength);
            return output;
        }
    }
}

Examples of calling the code can be found in these tests:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Gists.Extensions.ListOfTExtentions;

namespace Gists_Tests.ExtensionTests.ListOfTExtentionTests
{
    [TestClass]
    public class ListOfT_ToDelimitedTextTests
    {
        #region Mock Data

        private class SimpleObject
        {
            public int Id { get; set; }
        }

        private class ComplextObject : SimpleObject
        {
            public string Name { get; set; }
            public bool Active { get; set; }
        }

        #endregion

        #region Tests

        [TestMethod]
        public void ToDelimitedText_ReturnsCorrectNumberOfRows()
        {
            // ARRANGE
            var itemList = new List<ComplextObject>
            {
                new ComplextObject {Id = 1, Name = "Sid", Active = true},
                new ComplextObject {Id = 2, Name = "James", Active = false},
                new ComplextObject {Id = 3, Name = "Ted", Active = true},
            };
            const string delimiter = ",";
            const int expectedRowCount = 3;
            const bool trimTrailingNewLineIfExists = true;

            // ACT
            string result = itemList.ToDelimitedText(delimiter, trimTrailingNewLineIfExists);
            var lines = result.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            var actualRowCount = lines.Length;

            // ASSERT
            Assert.AreEqual(expectedRowCount, actualRowCount);
        }

        [TestMethod]
        public void ToDelimitedText_ReturnsCorrectNumberOfProperties()
        {
            // ARRANGE
            var itemList = new List<ComplextObject>
            {
                new ComplextObject {Id = 1, Name = "Sid", Active = true}
            };
            const string delimiter = ",";
            const int expectedPropertyCount = 3;

            // ACT
            string result = itemList.ToDelimitedText(delimiter);
            var lines = result.Split(Environment.NewLine.ToCharArray());
            var properties = lines.First().Split(delimiter.ToCharArray());
            var actualPropertyCount = properties.Length;

            // ASSERT
            Assert.AreEqual(expectedPropertyCount, actualPropertyCount);
        }

        [TestMethod]
        public void ToDelimitedText_RemovesTrailingNewLine_WhenSet()
        {
            // ARRANGE
            var itemList = new List<ComplextObject>
            {
                new ComplextObject {Id = 1, Name = "Sid", Active = true},
                new ComplextObject {Id = 2, Name = "James", Active = false},
                new ComplextObject {Id = 3, Name = "Ted", Active = true},
            };
            const string delimiter = ",";
            const bool trimTrailingNewLineIfExists = true;

            // ACT
            string result = itemList.ToDelimitedText(delimiter, trimTrailingNewLineIfExists);
            bool endsWithNewLine = result.EndsWith(Environment.NewLine);

            // ASSERT
            Assert.IsFalse(endsWithNewLine);
        }

        [TestMethod]
        public void ToDelimitedText_IncludesTrailingNewLine_WhenNotSet()
        {
            // ARRANGE
            var itemList = new List<ComplextObject>
            {
                new ComplextObject {Id = 1, Name = "Sid", Active = true},
                new ComplextObject {Id = 2, Name = "James", Active = false},
                new ComplextObject {Id = 3, Name = "Ted", Active = true},
            };
            const string delimiter = ",";
            const bool trimTrailingNewLineIfExists = false;

            // ACT
            string result = itemList.ToDelimitedText(delimiter, trimTrailingNewLineIfExists);
            bool endsWithNewLine = result.EndsWith(Environment.NewLine);

            // ASSERT
            Assert.IsTrue(endsWithNewLine);
        }

        #endregion
    }
}

Pass each string array collection to this function and this will return a CSV formatted string that you can either save to a large string buffer or write line by line to a file.

C#

public string CSVout(string[] strArray)
{
    string sOut = "";

    foreach (void s_loopVariable in strArray) {
        s = s_loopVariable;
        if (s.Contains(","))
            s = Strings.Chr(34) + s + Strings.Chr(34);
        sOut += s + ",";
    }

    if (Strings.Right(sOut, 1) == ",")
        sOut = Strings.Left(@out, @out.Length - 1);

    return sOut;
}

VB.NET:

  Function CSVout(strArray() As String) As String
    Dim out As String = ""

    For Each s In strArray
        If s.Contains(",") Then s = Chr(34) + s + Chr(34)
        out &= s + ","
    Next

    If Strings.Right(out, 1) = "," Then out = Strings.Left(out, out.Length - 1)

    Return out
End Function
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top