LinqToExcel C# 自动将 CSV 值转换为 DATETIME

LinqToExcel C# Automatically casting CSV values to DATETIME

我目前正在使用 LinqToExcel 来解析有效的 CSV 文件,但是当我到达特定列(不是日期)时,它会自动转换为日期时间变量。示例:

2/010/114

将被选为

cc = "2/10/0114 12:00:00 AM"

这是我使用的代码:

var csv = new ExcelQueryFactory(filepath);

var records = from c in csv.Worksheet(0)
              let rows = new 
              {
                  cc = c[9].ToString(),
              }
              select rows;

我也尝试过以最原始的格式获取结果,但遇到了同样的问题:

var rawrecords = from c in csv.Worksheet()
                 select c;

这是设计使然吗?还是我做错了什么?如何确保保留原始字符串?好像有点奇怪的设计..

我以前没有使用过 Linq2Excel,但根据他们 GitHub 上的示例使用信息,我认为以下应该有效:

var csv = new ExcelQueryFactory(filepath);

var records = from c in csv.Worksheet(0)
              let rows = new 
              {
                  cc = c[9].Cast<string>(),
              }
              select rows;

更新

在 LinqPad 中尝试此代码后,我可以确认它不起作用,那是因为似乎没有任何方法可以强制它将该单元格解释为字符串,它看起来像 DateTime 所以它就是这样解释的。

我能看到让它做你想做的唯一方法是引用这些值,例如:

A,B
12,"2/010/114"

这会强制它正确读入。

简而言之,我想知道您是否真的需要 LinqToExcel 的复杂性,并且是否可以自己手动读取文件?


示例Reader

我整理了以下非常简单和 hacky reader:

void Main()
{
    var reader = new CsvReader();
    reader.Read(@"C:\users\clint\desktop\test.csv", 10, 5);
    reader.GetDataAtPosition(1,1).Dump();
    reader.GetDataAtPosition(2,2).Dump();
    reader.GetDataAtPosition(2,2, s => s.Split('/')).Dump();
}

// Define other methods and classes here
public class CsvReader
{
    private string[,] _data;
    
    // Take a file, and estimated col and row counts (over-inflate these if needed to ensure the file can be read)
    public void Read(string file, int cols, int rows)
    {
        _data = new string[rows,cols];
        GC.Collect(2);
        var line = 0;
        var col = 0;
        using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            using (var reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    var lineIn = reader.ReadLine();
                    var inQuotes = false;
                    var thisCellRaw = "";
                    foreach (var ch in lineIn.TrimStart().TrimEnd())
                    {
                        if (ch == '"')
                        {
                            inQuotes = !inQuotes;
                            continue;
                        }

                        if (ch == ',' && !inQuotes)
                        {
                            _data[line, col] = thisCellRaw;
                            thisCellRaw = "";
                            col++;
                            continue;
                        }
                        
                        thisCellRaw += ch;
                    }
                    if (!string.IsNullOrEmpty(thisCellRaw))
                    {
                        _data[line, col] = thisCellRaw;
                    }
                    line++;
                    col = 0;
                }
            }
        }
    }

    public string GetDataAtPosition(int row, int col)
    {
        return GetDataAtPosition<string>(row,col);
    }
    
    public T GetDataAtPosition<T>(int row, int col, Func<string,T> transform = null)
    {
        row = row - 1;
        col = col - 1;
        var item = _data[row,col];
        if (item == null) throw new KeyNotFoundException("No data at that position");
        return (transform ?? ((s) => (T)Convert.ChangeType(item, typeof(T))))(item);
    }
}

它不是最有效的,不应该在生产代码中使用而不进行一些认真的清理和错误处理,但这应该有助于您实现目标;您甚至可以使用某种形式的推理,例如int.TryParse 测试是否应将某些内容视为 int 等