0

我找到了一个将 csv 文件与 linq 连接起来的库。我理解了这些原则,并且我的代码运行良好。但我对大 csv 文件有一些问题。

http://www.codeproject.com/Articles/25133/LINQ-to-CSV-library

现在我想从我的 _dataTable 对象访问特定的单个项目。我得到它们是这样的:

public class CsvFile
{  
    private IEnumerable<DataRow> _dataTable = cc.Read<DataRow>(_filePath, _inputFileDescription);
    public string GetItem(int row, int column)
    {
        return _dataTable.ElementAt<DataRow>(row).ElementAt<DataRowItem>(column).Value;
    }
}

当我现在在循环中调用这样的方法时:

CsvFile file1 = new CsvFile("C:\\dev_csvcompare\\Master.csv", ';', true);
for(int i = 0; i < 10000; i++)
    {
        string dummy = file1.GetItem(1, i);  //Does not make sense, my loop is a bit more complicated
    }

它变得非常慢,因为 IEnumerable 每次调用都会打开流。

在“延迟阅读”下的文档(链接)中,他们说我可以使用 foreach 循环访问可枚举的“_dataTable”(这确实工作正常),但在我的情况下这是没有选择的,因为我想访问 csv 中的特定项目.

是否有可能保持文件流打开以提高性能?

编辑(我的代码,也许很多废话,我对 .net、c# 和 oop 没有那么经验):

    public void Compare(int key1, int key2, int col1, int col2)
            {
                string lastKeyCol1 = null;
                string lastKeyCol2 = null;

                List<string> sortedKeyColFile1 = new List<string>();
                List<string> sortedKeyColFile2 = new List<string>();

                int file1counter = 0;
                int file2counter = 0;

                int cnt = 0;

                sortedKeyColFile1 = _file1.GetCol(key1);
                sortedKeyColFile1.Sort();

                sortedKeyColFile2 = _file2.GetCol(key2);
                sortedKeyColFile2.Sort();

                while ((file1counter < sortedKeyColFile1.Count) || (file2counter < sortedKeyColFile2.Count))
                {
                    _outputList.Add(new OutputValues(key1, key2, col1, col2));
                    //Keys are in both files
                    if (sortedKeyColFile1[file1counter] == sortedKeyColFile2[file2counter])
                    {                   
                        if (lastKeyCol1 == sortedKeyColFile1[file1counter])
                        {
                            //Keys are redundant
                            _outputList[cnt].RedundantKeyF1 = true;
                        }               
                        if (lastKeyCol2 == sortedKeyColFile2[file2counter])
                        {
                            //Keys are redundant
                            _outputList[cnt].RedundantKeyF2 = true;
                        }
                        lastKeyCol1 = sortedKeyColFile1[file1counter];
                        lastKeyCol2 = sortedKeyColFile2[file2counter];

                        _outputList[cnt].ValF1 = _file1.GetItem(file1counter, col1);
                        _outputList[cnt].ValF2 = _file2.GetItem(file2counter, col2);
                        _outputList[cnt].LineNumF1 = file1counter;
                        _outputList[cnt].LineNumF2 = file2counter;

                        //compare the values (because keys do match at this place)
                        _outputList[cnt].CompareResult = CompareString(_file1.GetItem(file1counter, col1), _file2.GetItem(file2counter, col2));

                        if (file1counter < sortedKeyColFile1.Count)
                        {
                            file1counter++;
                        }
                        if (file2counter < sortedKeyColFile2.Count)
                        {
                            file2counter++;
                        }
                    }
                    //Key sortedKeyColFile2[file2counter] is not in file 1
                    else if (file2counter < sortedKeyColFile2.Count && 0 < (string.Compare(sortedKeyColFile1[file1counter], sortedKeyColFile2[file2counter])))
                    {
                        _outputList[cnt].LineNumF2 = file2counter;
                        if (lastKeyCol2 == sortedKeyColFile2[file2counter])
                        {
                            //Keys are redundant
                            _outputList[cnt].RedundantKeyF2 = true;
                        }
                        lastKeyCol2 = sortedKeyColFile2[file2counter];
                        file2counter++;
                    }
                    //Key sortedKeyColFile1[file1counter] is not in file 2
                    else if (file1counter < sortedKeyColFile1.Count)
                    {
                        _outputList[cnt].LineNumF1 = file1counter;
                        if (lastKeyCol1 == sortedKeyColFile1[file1counter])
                        {
                            //Keys are redundant
                            _outputList[cnt].RedundantKeyF1 = true;
                        }
                        lastKeyCol1 = sortedKeyColFile1[file1counter];
                        file1counter++;
                    }
                    cnt++;
                }
            }

//And here the important part of the csv-file class, maybe not so interesting
    public class CsvFile
    {
        private string _filePath = null;
        private char _separator = ',';
        private bool _hasHeader = true;
        private CsvContext _cc = null;
        private CsvFileDescription _inputFileDescription = null;
        private List<string> _headers = null;
        private IEnumerable<DataRow> _dataTable = null;

        /// <summary>
        /// Constructor for a new CsvFile object. 
        /// The Constructor initiates the Object and read the values out of the File
        /// </summary>
        /// <param name="filePath">Full path of the csv-file</param>
        /// <param name="separator">Seperator of the csv-file, eg: ';' or ',' or '\t'</param>
        /// <param name="hasHeader">Is true if the first col of the csv-file contains a headers</param>
        public CsvFile(string filePath, char separator, bool hasHeader = true)
        {
            //Throws an exception if something is wrong with the file
            File.OpenRead(filePath);

            _filePath = filePath;
            _separator = separator;
            _hasHeader = hasHeader;
            _cc = new CsvContext();
            _inputFileDescription = new CsvFileDescription
            {
                SeparatorChar = separator,
                FirstLineHasColumnNames = hasHeader
            };

            _dataTable = _cc.Read<DataRow>(_filePath, _inputFileDescription);

            if (hasHeader)
            {
                ParseHeaders();
            }
        }
        public List<string> GetCol(int col)
        {
            List<string> column = new List<string>();
            int cnt = 0;
            foreach(DataRow x in _dataTable)
            {
                column.Add(x[col].Value);
                cnt++;
            }
            return column;
        }
        private void ParseHeaders()
        {
            System.IO.StreamReader file = new System.IO.StreamReader(_filePath);
            if (!file.EndOfStream)
            {
                //_headers = file.ReadLine().Split(_separator);

                _headers = new List<string> (file.ReadLine().Split(_separator));
            }
            file.Close();
        }
    }
4

1 回答 1

0

尝试这个:

public class CsvFile
{  
    private IEnumerable<DataRow> rows = cc.Read<DataRow>(_filePath, _inputFileDescription);
    //...       
    public IEnumerable<DataRow> Rows { get { return rows; } }

}

接着:

CsvFile file1 = new CsvFile("C:\\dev_csvcompare\\Master.csv", ';', true);
foreach(DataRow row in file1.Rows)
{
    string dummy = row[1];
}
于 2013-10-09T15:50:53.537 回答