在C#中读取文本文件的最快方法

时间:2014-01-05 14:09:36

标签: c# regex file-io

我正在处理一个项目,我有点困惑。我从我的老师那里得到了一些txt文件(来自his site文件:wt40.txt,wt50.txt,wt100.txt)。

每个文件结构都类似:

26    24    79    46    32    35    73    74    14    67    86    46    78    40    29    94    64    27    90    55
35    52    36    69    85    95    14    78    37    86    44    28    39    12    30    68    70     9    49    50
 1    10     9    10    10     4     3     2    10     3     7     3     1     3    10     4     7     7     4     7
 5     3     5     4     9     5     2     8    10     4     7     4     9     5     7     7     5    10     1     3
  • 每个数字都有6个字符,但不是前导零 空间
  • 每行有20个数字

文件wt40.txt应该读作:前两行到第一列,下两行到下一列,第三对到第三列。下一行应该再次与这些列表成对。

在C ++中,我是以这种简单的方式做到的:

for(int ins=0; ins<125; ins++) //125 instances in file
{
    for(int i=0; i<N; i++)  file>>tasks[i].p; //N elements at two first lines
    for(int i=0; i<N; i++)  file>>tasks[i].w;
    for(int i=0; i<N; i++)  file>>tasks[i].d;
    tasks[i].putToLists();
}

但是当我在C#中编写它时,我必须打开StreamReader,读取每一行,用regexp拆分它们,将它们转换为int并添加到列表中。这是很多循环。 我无法读取每6个字符并将它们添加到三个循环中,因为那些文本文件已经搞乱了行字符的结尾 - 有时它只是'\ n'有时更多。

有没有更简单的方法?

2 个答案:

答案 0 :(得分:1)

基本上有一个20位数的6位数(字符)数字表,带有前导空格。

26    24    79    46    32    35    73    74    14    67    86    46    78    40    29    94    64    27    90    55
35    52    36    69    85    95    14    78    37    86    44    28    39    12    30    68    70     9    49    50
 1    10     9    10    10     4     3     2    10     3     7     3     1     3    10     4     7     7     4     7
 5     3     5     4     9     5     2     8    10     4     7     4     9     5     7     7     5    10     1     3

我不明白最后一句:

  

文件wt40.txt应该读作:前两行到第一列,下一行   两行到下一个列表和第三对行到第三列表。下一个   再次将这些行与这些列表成对出现。

假设您想获得前6行并创建3个列表,每个列有2行,您可以这样做:

它渴望将所有内容读入内存然后完成其工作。

const int maxNumberDigitLength = 6;
const int rowLengthInChars = maxNumberDigitLength * 20;
const int totalNumberOfCharsToRead = rowLengthInChars * maxNumberDigitLength;

char[] buffer = new char[totalNumberOfCharsToRead];
using (StreamReader reader = new StreamReader("wt40.txt")
{
    int numberOfCharsRead = reader.Read(buffer, 0, totalNumberOfCharsToRead);
}

// put them in your lists
IEnumerable<char> l1 = buffer.Take(rowLengthInChars);
IEnumerable<char> l2 = buffer.Skip(rowLengthInChars).Take(rowLengthInChars);
IEnumerable<char> l3 = buffer.Skip(rowLengthInChars*2).Take(rowLengthInChars);

// Get the list of strings from the list of chars using non LINQ method.
List<string> list1 = new List<string>();
int i = 0;
StringBuilder sb = new StringBuilder();
foreach(char c in l1)
{
    if(i < maxNumberDigitLength)
    {
        sb.Append(c);
        i++;
    }
    i = 0;
    list1.Add(sb.ToString());
}

// LINQ method
string s = string.Concat(l1);
List<string> list1 = Enumerable
                   .Range(0, s.Length / maxNumberDigitLength)
                   .Select(i => s.Substring(i * maxNumberDigitLength, maxNumberDigitLength))
                   .ToList();     

// Parse to ints using LINQ projection
List<int> numbers1 = list1.Select(int.Parse);
List<int> numbers2 = list2.Select(int.Parse);
List<int> numbers3 = list3.Select(int.Parse);

答案 1 :(得分:1)

  

还有更简单的方法吗?

不知道它是否更简单,但只有一个循环和一点LINQ

List<List<int>> lists = new List<List<int>>();
using (StreamReader reader = new StreamReader("wt40.txt"))
{
    string line;
    int count = 0;
    while ((line = reader.ReadLine()) != null)
    {
        List<int> currentList =
            Regex.Split(line, "\\s")
            .Where(s => !string.IsNullOrWhiteSpace(s))
            .Select(int.Parse).ToList();
        if (currentList.Count > 0) // skip empty lines
        {
            if (count % 2 == 0) // append each second list to the previous one
            {
                lists.Add(currentList);
            }
            else
            {
                lists[count / 2].AddRange(currentList);
            }
        }
        count++;
    }
}

总共最终得到375个列表,每个列表包含40个数字(至少用于wt40.txt输入)。