C#在.csv文件中添加具有相同Date.Time的行

时间:2018-11-22 14:22:02

标签: c# csv

我当前正在编写一个跟踪某些内容(基本INT值和保存它们的日期)的程序。

我的目标是将具有相同日期的INT值相加。

20.11.2018 00:00:00; 1;1;1;1;1
20.11.2018 00:00:00; 1;1;1;1;1
22.11.2018 00:00:00; 1;1;1;1;1

基本上应该像这样

20.11.2018 00:00:00; 2;2;2;2;2
22.11.2018 00:00:00; 1;1;1;1;1

保存数据,甚至将2条“行”加在一起也很好。

问题在于,当我将两行加在一起时,带有1的2行显然不会被删除。

这是比较日期并将行加在一起的方法:

public static Dictionary<DateTime, int[]> CompareDateMethod(Dictionary<DateTime, int[]> oDateTimeAndIntDictionary,string[][] ReadData)
{
    Dictionary<DateTime, int[]> oPrintRealData = new Dictionary<DateTime, int[]>();
    Dictionary<DateTime, int[]> oAddRealData = new Dictionary<DateTime, int[]>();

    for (int i = 0 ; i < ReadData.Length; i++)
    {
        DateTime dtDateValue;
        if (DateTime.TryParse(ReadData[i][0], out dtDateValue))     
        {
            int[] iValuesToAdd = ConvertArrayToInt(ReadData[i]);

            if (dtDateValue.Date == DateTime.Now.Date)                   
            {
                for (int j = 0; j < iValuesToAdd.Length; j++)
                {
                    oDateTimeAndIntDictionary[dtDateValue.Date][j] += iValuesToAdd[j];      
                }
            }
            else if (dtDateValue.Date != DateTime.Now.Date)                              
            {
                goto Endloop;                                   
            }
        }
    }
    Endloop:
    return oDateTimeAndIntDictionary;  

这是将数据写入.CSV文件的方法

    Dictionary<DateTime, int[]> oDateTimeAndIntDictionary = new Dictionary<DateTime, int[]>();
    string[][] OldData= AddVariables.ReadOldData();
    int[] iNewDataArray = new int[] { iVariable1, iVariable2, iVariable3, iVariable4, iVariable5};

    oDateTimeAndIntDictionary.Add(DateTime.Now.Date, iNewDataArray);

    using (System.IO.FileStream fileStream = new System.IO.FileStream(@"C: \Users\---\Csvsave\SaveDatei.csv", System.IO.FileMode.Append, System.IO.FileAccess.Write))
    using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileStream))
    {
        foreach (KeyValuePair<DateTime, int[]> kvp in AddVariables.CompareDateMethod(oDateTimeAndIntDictionary, OldData))
        {
                streamWriter.WriteLine("{0}; {1}", kvp.Key, string.Join(";", kvp.Value));
        }
    }

我非常想出一些办法,但没有任何效果(我尝试从.csv中删除行似乎很困难,我尝试向后读取文件,但行不通,等等)

如果有人可以给我一些指导,我将非常感激。

4 个答案:

答案 0 :(得分:1)

我认为原始代码的问题在于何时发生的事情有点令人困惑。我已经对其进行了重组,以使事情按逻辑顺序发生(并对其进行了一些更新,简化了变量名等)。有一个用于合并具有相同日期的行的功能,该功能与CSV编写代码(未更改)是分开的

static void Main(string[] args)
    {
        var oldData = ReadOldData();

        // Do the work
        var results = SumValuesForSameDate(oldData);

        // Write the file
        using (System.IO.FileStream fileStream = new System.IO.FileStream(@"C: \Users\---\Csvsave\SaveDatei.csv", System.IO.FileMode.Append, System.IO.FileAccess.Write))
        using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileStream))
        {
            foreach (KeyValuePair<DateTime, int[]> kvp in results)
            {
                streamWriter.WriteLine("{0}; {1}", kvp.Key, string.Join(";", kvp.Value));
            }
        }
    }

    public static Dictionary<DateTime, int[]> SumValuesForSameDate(string[][] readData)
    {
        var oDateTimeAndIntDictionary = new Dictionary<DateTime, int[]>();

        var currentDate = DateTime.MinValue;

        foreach (var row in readData)
        {
            DateTime dateValue;
            if(!DateTime.TryParse(row[0], out dateValue)) continue;

            dateValue = dateValue.Date;

            var intValues = ConvertArrayToInt(row);

            if (dateValue == currentDate)
            {
                for (var j = 0; j < intValues.Length; j++)
                {
                    oDateTimeAndIntDictionary[dateValue][j] += intValues[j];
                }
            }
            else
            {
                oDateTimeAndIntDictionary.Add(dateValue, intValues);
                currentDate = dateValue;
            }
        }

        return oDateTimeAndIntDictionary;
    }

    static int[] ConvertArrayToInt(string[] strings)
    {
        var output = new int[strings.Length - 1];
        for (var i = 1; i < strings.Length; i++)
        {
            output[i - 1] = int.Parse(strings[i]);
        }

        return output;
    }

    static string[][] ReadOldData()
    {
        // Fake data
        var data = new string[][]
        {
            new string[] { "20.11.2018 00:00:00", "1", "1", "1", "1", "1"  },
            new string[] { "20.11.2018 00:00:00", "1", "1", "1", "1", "1"  },
            new string[] { "22.11.2018 00:00:00", "1", "1", "1", "1", "1"  },
        };
        return data;
    }
}

答案 1 :(得分:0)

要覆盖以前的CSV,只需使用System.IO.FileMode.Create而不是Append。这将覆盖以前的所有数据。

答案 2 :(得分:0)

无论如何,您都需要覆盖csv才能摆脱已写入的行。 因此,与其返回oDateTimeAndIntDictionary并覆盖CompareDateMethod的解析值,不如从ReadData方法中返回ReadData

这样的事情,

public static Dictionary<DateTime, int[]> CompareDateMethod(Dictionary<DateTime, int[]> oDateTimeAndIntDictionary,string[][] ReadData)
{
    Dictionary<DateTime, int[]> oPrintRealData = new Dictionary<DateTime, int[]>();
    Dictionary<DateTime, int[]> oAddRealData = new Dictionary<DateTime, int[]>();

    for (int i = 0 ; i < ReadData.Length; i++)
    {
        DateTime dtDateValue;
        if (DateTime.TryParse(oDateTimeAndIntDictionary[0][0], out dtDateValue))     
        {
            int[] iValuesToAdd = ConvertArrayToInt(ReadData[i]);

            if (dtDateValue.Date == DateTime.Now.Date)                   
            {
                for (int j = 0; j < iValuesToAdd.Length; j++)
                {
                    //Add the ReadData values here and store at ReadData[i][j]
                }
            }
        else if (dtDateValue.Date != DateTime.Now.Date)                              
        {
            goto Endloop;                                   
        }
    }
}
Endloop:
return ReadData;
}

希望这对您有帮助...

答案 3 :(得分:0)

我阅读了您关于不使用linq和第3部分lib的评论。
但让我向您展示您所缺少的内容。
这是Linq + CSVHelper

首先,请定义您的数据,并定义如何在CSV中映射它们

public sealed class data
{
    public DateTime TimeStamp { get; set; }
    public List<int> Numbers { get; set; }
}

public sealed class dataMapping : ClassMap<data>
{
    public dataMapping()
    {
        Map(m => m.TimeStamp).Index(0);
        Map(m => m.Numbers)
            .ConvertUsing(
                row =>
                new List<int> {
                    row.GetField<int>(1),
                    row.GetField<int>(2),
                    row.GetField<int>(3)
                }
            );
    }
}

现在这是一个简短的演示:

class CsvExemple
{
    string inputPath = "datas.csv";
    string outputPath = "datasOut.csv";

    List<data> datas;
    public void Demo()
    {
        //no duplicate row in orginal input
        InitialiseFile();

        LoadExistingData();

        //add some new row and some dupe
        NewDatasArrived();

        //save to an other Path, to Compare. 
        SaveDatas();
    }

    private void SaveDatas()
    {
        using (TextWriter writer = new StreamWriter(outputPath))
        using (var csvWriter = new CsvWriter(writer))
        {
            csvWriter.Configuration.RegisterClassMap<dataMapping>();
            csvWriter.Configuration.Delimiter = ";";
            csvWriter.Configuration.HasHeaderRecord = false;
            csvWriter.WriteRecords(datas);
        }
    }

    static List<int> SuperZip(params List<int>[] sourceLists)
    {
        for (var i = 1; i < sourceLists.Length; i++)
        {
            sourceLists[0] = sourceLists[0].Zip(sourceLists[i], (a, b) => a + b).ToList();
        }
        return sourceLists[0];
    }

    private void NewDatasArrived()
    {
        var now = DateTime.Today;

        // New rows
        var outOfInitialDataRange = Enumerable.Range(11, 15)
                            .Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });
        // Duplicate rows
        var inOfInitialDataRange = Enumerable.Range(3, 7)
                            .Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });

        //add all of them them together
        datas.AddRange(outOfInitialDataRange);
        datas.AddRange(inOfInitialDataRange);

        // all this could have been one Line
        var grouped = datas.GroupBy(x => x.TimeStamp);

        var temp = grouped.Select(g => new { TimeStamp = g.Key, ManyNumbers = g.Select(x => x.Numbers).ToArray() });

        // We can combine element of 2 list using Zip. ListA.Zip(ListB, (a, b) => a + b)
        datas = temp.Select(x => new data { TimeStamp = x.TimeStamp, Numbers = SuperZip(x.ManyNumbers) }).ToList();
    }

    private void LoadExistingData()
    {
        if (File.Exists(inputPath))
        {
            using (TextReader reader = new StreamReader(inputPath))
            using (var csvReader = new CsvReader(reader))
            {
                csvReader.Configuration.RegisterClassMap<dataMapping>();
                csvReader.Configuration.HasHeaderRecord = false;
                csvReader.Configuration.Delimiter = ";";

                datas = csvReader.GetRecords<data>().ToList();
            }
        }
        else
        {
            datas = new List<data>();
        }
    }

    private void InitialiseFile()
    {
        if (File.Exists(inputPath))
        {
            return;
        }

        var now = DateTime.Today;
        var ExistingData = Enumerable.Range(0, 10)
                            .Select(x => new data { TimeStamp = now.AddDays(-x), Numbers = new List<int> { x, x, x } });

        using (TextWriter writer = new StreamWriter(inputPath))
        using (var csvWriter = new CsvWriter(writer))
        {
            csvWriter.Configuration.RegisterClassMap<dataMapping>();
            csvWriter.Configuration.Delimiter = ";";
            csvWriter.Configuration.HasHeaderRecord = false;
            csvWriter.WriteRecords(ExistingData);
        }
    }
}