使用泛型类定义导入数据文件

时间:2011-02-17 01:20:52

标签: c# generics file-io

我正在尝试导入一个包含多个记录定义的文件。每个人也可以有一个标题记录,所以我想我会定义一个这样的定义界面。

public interface IRecordDefinition<T>
{
    bool Matches(string row);
    T MapRow(string row);
    bool AreRecordsNested { get; }
    GenericLoadClass ToGenericLoad(T input);
}

然后我为一个类创建了一个具体的实现。

public class TestDefinition : IRecordDefinition<Test>
{
    public bool Matches(string row)
    {
        return row.Split('\t')[0] == "1";
    }

    public Test MapColumns(string[] columns)
    {
        return new Test {val = columns[0].parseDate("ddmmYYYY")};
    }

    public bool AreRecordsNested
    {
        get { return true; }
    }

    public GenericLoadClass ToGenericLoad(Test input)
    {
        return new GenericLoadClass {Value = input.val};
    }
}

但是对于每个文件定义,我需要存储一个记录定义列表,这样我就可以遍历文件中的每一行并相应地处理它。

首先,我是在正确的轨道上 或者有更好的方法吗?

3 个答案:

答案 0 :(得分:3)

您是否使用Linq查看了某些内容?这是Linq to Text和Linq to Csv的快速示例。

我认为使用“yield return”和IEnumerable来获得你想要的工作要简单得多。这样你就可以在界面上只有1个方法。

答案 1 :(得分:3)

我会把这个过程分成两部分。

首先,将具有多种类型的文件拆分为多个文件的特定进程。如果文件是固定宽度的,那么我对正则表达式有很多好运。例如,假设以下是具有三种不同记录类型的文本文件。

TE20110223 A 1
RE20110223 BB 2
CE20110223 CCC 3

你可以看到这里有一个模式,希望决定将所有记录类型放在同一个文件中的人给你一种识别这些类型的方法。在上面的例子中,您将定义三个正则表达式。

string pattern1 = @"^TE(?<DATE>[0-9]{8})(?<NEXT1>.{2})(?<NEXT2>.{2})";
string pattern2 = @"^RE(?<DATE>[0-9]{8})(?<NEXT1>.{3})(?<NEXT2>.{2})";
string pattern3 = @"^CE(?<DATE>[0-9]{8})(?<NEXT1>.{4})(?<NEXT2>.{2})";

Regex Regex1 = new Regex(pattern1);
Regex Regex2 = new Regex(pattern2);
Regex Regex3 = new Regex(pattern3);

StringBuilder FirstStringBuilder = new StringBuilder();
StringBuilder SecondStringBuilder = new StringBuilder();
StringBuilder ThirdStringBuilder = new StringBuilder();

string Line = "";
Match LineMatch;


FileInfo myFile = new FileInfo("yourFile.txt");

using (StreamReader s = new StreamReader(f.FullName))
{

    while (s.Peek() != -1)
    {
        Line = s.ReadLine();

        LineMatch = Regex1.Match(Line);
        if (LineMatch.Success)
        {
            //Write this line to a new file
        }

        LineMatch = Regex2.Match(Line);
        if (LineMatch.Success)
        {
            //Write this line to a new file
        }

        LineMatch = Regex3.Match(Line);
        if (LineMatch.Success)
        {
            //Write this line to a new file
        }
    }
}

接下来,获取拆分文件并通过您最有可能已经拥有的通用进程运行它们来导入它们。这很有效,因为当进程不可避免地失败时,您可以将其缩小到失败的单个记录类型,而不会影响所有记录类型。将主文本文件与拆分文件一起存档,您的生活也将变得更加容易。

处理这些传输的文件很难,因为其他人控制它们,你永远不知道它们什么时候会改变。记录原始文件以及导入的收据非常重要,也不应该被忽视。您可以根据需要将其设置为简单或复杂,但我倾向于将收据写入数据库并将该表中的主键复制到我已导入数据的表中的外键中,然后 never 更改该数据。我喜欢在文件系统和数据库服务器上保留一个不受干扰的导入副本,因为您需要跟踪不可避免的转换/转换问题。

希望这会有所帮助,因为这不是一项微不足道的任务。我认为你是在正确的轨道上,而不是分别处理/导入每一行...将它们写入一个单独的文件。我假设这是财务数据,这是我认为每一步的可证明性都很重要的原因之一。

答案 2 :(得分:3)

我认为FileHelpers库解决了许多问题:

我确信你可以将它整合到一个类型层次结构中,也可以绑定自定义二进制格式。