基于List <order> orders集合</order>的棘手CSV文件输出

时间:2009-12-30 01:45:06

标签: c# csv

我必须制作这种CSV布局,但有点不确定该怎么做。

我有一个Order类,我必须将其转换为CSV文件。

public class Order
{
       public int ID {get; set;}
       public int Created {get;set;}
       public List<Item> Items {get;set;}
}
public class Item
{
        public string Sku {get;set;}
        public int Quantity {get;set;}
}

所以每行代表一个订单。如果一个订单中有超过2个项目,我将不得不继续下一行,除了sku,quanity和一个特定字段外,所有内容都是空白的。

如果从前一行继续,则最后一个字段为“Y”,否则为“N”。

所以我有:

List<Order> orders = Db.GetOrders();

因此CSV的示例输出将是:

"orderID", "Created", "Item01", "quantity01", "Item02", "N"

如果有超过2个项目,则必须输出:

"orderID", "Created", "Item01", "quantity01", "Item02", "N"
"", "", "Item03", "quantity03", "", "", "Y"

所以上面的订单有3个项目,请注意Item#4的占位符是如何仍然存在的,但只是空的双引号。

所以每个字段都是强制性的。

我如何制作这个?

到目前为止,我有:

StringBuilder sb = new StringBuilder();

for(int x = 0; x < orders.Count; x++)
{
         Order o = orders[x];

         if(x % 2 = 0)
         {
           sb.Append(o.ID).Append(",");
           sb.Append(o.Created).Append(",");
         }

}

我猜的诀窍是弄清楚我是否需​​要继续下一行,然后如果我的行中少于2个项目,我必须填写任何空白点?

(你可以忽略输出中的任何不良字符,稍后我会处理)

4 个答案:

答案 0 :(得分:0)

你的内循环看起来像这样:

for (i = 0; i < items.Count; ++i) {
  sb.Append(sku)
  sb.Append(qty)
  if (i % 2 == 1) {
    if (i == items.Count - 1) {
      sb.Append("N\n")
    } else {
      sb.Append("Y\n" "" "");
    }
  }
}
if (items.Count == 0) {
  sb.Append("" "" "" "" "N")
}
if (items.Count % 2 == 1) {
  sb.Append("" "" "N")
}

你可以扩展伪代码... csv格式有点不寻常。通常,csv将包含一个项目列表,每行一个(每个行中重复的订单号)。

答案 1 :(得分:0)

我发现将这样的问题分解为几种方法是有帮助的,每种方法都很容易理解,只做一小部分工作。然后你可以将它们结合起来解决更大的问题。

这可以帮助您入门。它需要更多的错误处理,并且可能需要逻辑来处理生成CSV字段时转义特殊字符(例如,如果SKU中可能包含逗号或引号)。

    public class Order
    {
        public int ID { get; set; }
        public int Created { get; set; }
        public List<Item> Items { get; set; }
    }
    public class Item
    {
        public string Sku { get; set; }
        public int Quantity { get; set; }
    }

    public class OrderCsvBuilder
    {
        private readonly StringBuilder m_CsvData = new StringBuilder();

        // constructor accepts a sequence or Orders
        public OrderCsvBuilder(IEnumerable<Order> orders)
        {
            foreach (var order in orders)
                WriteOrder(order);
        }

        // returns the formatted CSV data as a string
        public string GetCsvData()
        {
            return m_CsvData.ToString();
        }

        // writes a single order and its line items to csv format
        private void WriteOrder( Order order )
        {
            WriteCsvFields( false, order.ID, order.Created );
            var itemIndex = 0;
            foreach( var item in order.Items )
                WriteOrderItem( item, itemIndex++ );
        }

        // writes a single order item to csv format
        private void WriteOrderItem( Item item, int itemIndex )
        {
            // write the extra fields when the order item is not the first item
            if( itemIndex > 0 )
                WriteCsvFields( false, string.Empty, string.Empty );
            // use (?:) to append indicator of whether item is first or additional
            WriteCsvFields( true, item.Quantity, item.Sku, itemIndex > 0 ? "Y" : "N" );
        }

        // writes a series of fields to the file in csv form
        private void WriteCsvFields( bool isLineEnd, params object[] fields )
        {
            // write each field to the StringBuilder in CSV format
            // TODO: Need better error handling and escaping of special characters
            foreach( var field in fields )
            {
                m_CsvData.AppendFormat("\"{0}\", ", field);
            }
            // trim extra trailing space and comma if this is the last item of a line
            if( isLineEnd )
                m_CsvData.Remove(m_CsvData.Length - 2, 2);
        }
    }

答案 2 :(得分:0)

public string BuildOrdersCsv(List<Order> orders)
{
    StringBuilder sb = new StringBuilder();

    foreach (Order o in orders)
    {
        Append(sb, o.ID, o.Created);
        for (int i = 0; i < 2; i++)
        {
            if (i < o.Items.Count)
                Append(sb, o.Items[i].Sku, o.Items[i].Quantity);
            else
                Append(sb, "", "");
        }
        sb.AppendLine("\"N\"");

        for (int i = 2; i < o.Items.Count; i++)
        {
            Append(sb, "", "", o.Items[i].Sku, o.Items[i].Quantity, "", "");
            sb.AppendLine("\"Y\"");
        }
    }

    return sb.ToString();
}

private void Append(StringBuilder sb, params object[] items)
{
    foreach (object item in items)
    {
        sb.Append("\"").Append(item).Append("\",");
    }
}

答案 3 :(得分:0)

未经测试,但你得到了这个小说。它可能无法完全按照您的要求进行操作,但很容易调整到您想要的内容。不需要所有的stringbuilder废话。

public class Order
{
    public int ID { get; set; }
    public int Created { get; set; }
    public List<Item> Items { get; set; }
    public override string ToString()
    {
        string fakeItem = "";
        if(Items.Count > 2) 
            fakeItem = Environment.NewLine + @""""", """", ""Y"" "; // or whatever you want.
        return string.Join(@"{0}, {1}, {2}, {3}", 
            ID, 
            Created == 0 ? "Y" : "N", 
            string.Join(", ", from item in Items.Take(2) select item.ToString()),
            fakeItem);
    }
}
public class Item
{
    public string Sku { get; set; }
    public int Quantity { get; set; }
    public override string ToString()
    {
        return string.Format(@"{0}, {1}", Sku, Quantity);
    }
}