【问题标题】:Working with csv file and DateTime using datatable in c# winforms在 c# winforms 中使用数据表处理 csv 文件和 DateTime
【发布时间】:2018-07-31 12:35:42
【问题描述】:

我有一个 .CSV 文件 (.csv file google drive link)。

我已经在 DataTable 中获取了 csv 文件的所有值。 现在我正在尝试做什么,我在下面解释:

我每 5 分钟在 csv 文件中找到 D 列的最低值。并且每个最小值将以 5 分钟的时间间隔插入到 L 列的第一行。 您可以从this csv file 获得想法。这个 csv 文件是输出文件。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Revision2
{
    public partial class Form1 : Form
    {
        DataTable datable = new DataTable();
        public Form1()
        {
            InitializeComponent();
        }

        private void browsebtm_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Select .CSV ffile";
            ofd.ShowDialog();
            txtboxpath.Text = ofd.FileName;
        }

        private void operatebtn_Click(object sender, EventArgs e)
        {
            string filePath = txtboxpath.Text;
            StreamReader sr = new StreamReader(filePath);
            string line = sr.ReadLine();
            string[] value = line.Split(',');

            DataRow row;
            foreach (string dc in value)
            {
                datable.Columns.Add(new DataColumn(dc));
            }
            while (!sr.EndOfStream)
            {
                value = sr.ReadLine().Split(',');
                if (value.Length == datable.Columns.Count)
                {
                    row = datable.NewRow();
                    row.ItemArray = value;
                    datable.Rows.Add(row);
                }
            }


            DateTime dt1 = DateTime.ParseExact(datable.Rows[0][1].ToString(), "dd-MM-yy HH:mm", CultureInfo.InvariantCulture);

            int totalRows = datable.Rows.Count;
            DateTime dt2 = DateTime.ParseExact(datable.Rows[totalRows - 1][1].ToString(), "dd-MM-yy HH:mm", CultureInfo.InvariantCulture);

            DateTime i, j;
            int r = 0, x = 0, z = 0, value1, value2 = 0;
            for (i = dt1; i <= dt2; i = i.AddMinutes(5))
            {
                DateTime dt5 = i.AddMinutes(5);
                if (dt5 >= dt2)
                    break;
                int y = 0;
                for (j = i; j < dt5; j = j.AddSeconds(1))
                {
                    y++;
                    for (r = x; r < 1669; r++)
                    {


                        string str1 = datable.Rows[r][1].ToString();
                        string str2 = j.ToString("dd-MM-yy HH:mm);
                        if (str1 == str2)
                        {

                            value1 = int.Parse(datable.Rows[r][3].ToString());
                            value2 = int.Parse(datable.Rows[x][3].ToString());
                            if (value2 > value1)
                            {
                                value2 = value1;
                            }
                            x++;
                        }
                    }
                    label2.Text = y.ToString();
                    if (r > 1669)
                        break;

                }
                datable.Rows[r][11] = value2;

            }
            label2.Text = i.ToString();
            //label1.Text = y.ToString();
            dataGridView1.DataSource = datable;
        }
    }
}

我做错了什么。当我单击操作按钮时,应用程序冻结。 我怎样才能改进我的代码来做到这一点。 我是新手。请帮忙

【问题讨论】:

  • 首先使用调试器逐步检查代码,以更准确地识别问题发生的位置,以及您在该点遇到的异常或其他意外行为(如果有)。
  • 在 DataTable 中大约有 1670 行...我如何通过断点检查这个
  • DataTable 不是此作业的正确控件。只需使用 Linq。
  • 那是什么?但问题不在 DataTable 中,问题出在循环某处。
  • Cetin 指出,如果您使用 Linq,您可能不需要循环。虽然对我来说如何使用 Linq 实现要求并不是很明显,但我想只要稍微考虑一下就可以了

标签: c# winforms csv


【解决方案1】:

使用 Linq 进行这些类型的转换更容易恕我直言。 这是 Linq 示例(我将您的 CSV 下载到 d:\temp\CRUDE1Minute.csv - 您可以复制并粘贴以下代码并在 LinqPad 添加 windows.forms 命名空间中运行它):

void Main()
{
    string fileName = @"d:\temp\CRUDE1Minute.csv";
    DateTime dt;
    var rawData = File.ReadAllLines(fileName)
        .Skip(1)
        .Select(line => line.Split(','))
        .Select(line => new
        {
            TradingSymbol = line[0],
            SnapshotDateTime = DateTime.TryParseExact(line[1], "dd-MM-yy HH:mm", null,
                     System.Globalization.DateTimeStyles.None, out dt) ? dt : (DateTime?)null,
            Open = int.Parse(line[2]),
            Low = int.Parse(line[3]),
            High = int.Parse(line[4]),
            Close = int.Parse(line[5]),
            Volume = int.Parse(line[6]),
            SnapshotDate = DateTime.TryParseExact(line[1], "dd-MM-yy HH:mm", null,
                    System.Globalization.DateTimeStyles.None, out dt) ? dt : (DateTime?)null,
            SnapshotTime = TimeSpan.Parse(line[8]),
            UpdateToDBTime = DateTime.TryParseExact(line[1], "dd-MM-yy HH:mm", null,
                    System.Globalization.DateTimeStyles.None, out dt) ? dt : (DateTime?)null,
        });
        var result =
    from myData in rawData.OrderBy(t => t.SnapshotDateTime)
    let min5 = ((int)myData.SnapshotDateTime.Value.TimeOfDay.TotalMinutes) / 5
    group myData by new
    {
        date = myData.SnapshotDateTime.Value.Date.AddMinutes(min5 * 5),
        min5
    } into barData
    select new
    {
        date = barData.Key.date,
        open = barData.Min( bd => bd.Open ),
        low = barData.Min(bd => bd.Low),
        high = barData.Min(bd => bd.High),
        close = barData.Min(bd => bd.Close)
    };

    var joined = from rd in rawData
                 join bd in result on rd.SnapshotDateTime equals bd.date into bdAdded
                 from d in bdAdded.DefaultIfEmpty()
    select           
    new {
         rd.TradingSymbol,
         rd.SnapshotDateTime,
         rd.Open,
         rd.Low,
         rd.High,
         rd.Close,
         rd.Volume,
         rd.SnapshotDate,
         rd.SnapshotTime,
         rd.UpdateToDBTime,
         bdOpen = d?.open,
         bdLow = d?.low,
         bdHigh = d?.high,
         bdClose = d?.close

    };


    // Show the result
    Form f = new Form();
    var dgv = new DataGridView {Dock=DockStyle.Fill, DataSource=joined.ToList()};
    f.Controls.Add( dgv);
    f.Show();
}

编辑:顺便说一句,我不清楚你在那些 5 分钟开盘、低点、...上选择什么,并且可能是错误的。也许你想做:

...
select new
{
    date = barData.Key.date,
    open = barData.First().Open, //barData.Min( bd => bd.Open ),
    low = barData.Min(bd => bd.Low),
    high = barData.Max(bd => bd.High),
    close = barData.Last().Close
};

【讨论】:

  • 你怎么知道我的所有要求?
  • 对我帮助很大
【解决方案2】:

试试这个循环例程。我通常将嵌套限制在 3 层。在您的情况下,您有 5 个,并且非常难以遵循。

int startIndex = 0;
while (startIndex < dt.Rows.Count)
{
    DateTime timeStart = DateTime.ParseExact(dt.Rows[startIndex][1].ToString(), "dd-MM-yy HH:mm",
        CultureInfo.InvariantCulture);
    DateTime timeEnd = timeStart;
    int lowestValue = int.Parse(dt.Rows[startIndex][3].ToString());
    int endIndex = startIndex;

    //loop to find end index of 5 minute loop
    for (int j = startIndex++; j < dt.Rows.Count; j++)
    {
        endIndex = j;
        timeEnd = DateTime.ParseExact(dt.Rows[endIndex][1].ToString(), "dd-MM-yy HH:mm",
            CultureInfo.InvariantCulture);
        if ((timeEnd - timeStart).TotalMinutes > 5)
        {
            break;
        }
        int newValue = int.Parse(dt.Rows[endIndex][3].ToString());
        if (newValue < lowestValue)
        {
            lowestValue = newValue;
        }
    }

    //loop from start to end to set lowest value
    for (var k = startIndex; k < endIndex; k++)
    {
        dt.Rows[k][11] = lowestValue.ToString();
    }

    startIndex = endIndex;
}

【讨论】:

    猜你喜欢
    • 2012-12-22
    • 2016-04-23
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    相关资源
    最近更新 更多