如何使用FileHelpers库导入CSV文件时修复ConvertException错误

3
我正在处理一个csv文件,由于用户输入错误,偶尔会在int字段中出现文本。它是第一列,基本上应该是唯一的记录ID。我使用engine.ErrorManager.ErrorMode = ErrorMode.SaveAndContinue;捕获错误。
我更愿意忽略错误,并用我选择的数字值替换文本,并仍然包括该行在处理结果中。
即使过程只是将我在文件定义类文件中声明的默认值插入:[FieldNullValue(typeof(int), "0")],我也可以接受。
还有一件事是我正在运行时确定要解析哪个文件:
Type t = assembly.GetType(assemblyName.Name + ".FileDefinitions." + className);  

FileHelperEngine engine = new FileHelperEngine(t);   

我不确定如何在需要填写<CustomersFixedWithNumericId>的情况下实现D.Lambert的建议。为了澄清一下,有7个不同的文件定义(类文件)被上传/处理,但它们都有CustomerId字段。


那是最糟糕的想法之母。现在这是你的问题了。 - Hans Passant
无论如何,这是我的问题。我需要清洗数据(全部数据),并让用户知道问题所在。由于我将CSV读入DataTable中,我想为什么不保留所有记录的行顺序,并向用户显示该字段的记录存在问题。 - Breadtruck
1个回答

2
鉴于目前FileHelpers的状态,您确实需要将该字段定义为字符串,并尝试自行验证其有效性。
我尝试了几种不同的解决方法--首先,我尝试使用属性而不是字段来设置记录。这可能使您能够创建一个字符串属性并在设置时验证输入。但这很困难,因为:
- 属性仅针对字段设置属性(如果您想修改FileHelpers代码,则相当容易修复)。 - 用于属性的私有字段必须标记为[FieldNotInFile]属性(很烦人)。 - RecordInfo.CreateCoreFields()方法不处理属性。要修复这个问题,您真的需要按正确的顺序创建属性和字段的合并列表。这是我停止研究该方法的点。
接下来的计划:按原样使用记录定义,并在读取期间进行验证。在引擎上设置事件处理程序:
    engine.AfterReadRecord += new Events.AfterReadHandler<CustomersFixedWithNumericId>(engine_AfterReadRecord);
    var res = engine.ReadFile(path);

然后在处理程序中处理错误值:

    void engine_AfterReadRecord(EngineBase engine, Events.AfterReadEventArgs<CustomersFixedWithNumericId> e)
    {
        int intVal;
        int.TryParse(e.Record.CustomerID, out intVal);
        e.Record.CustomerID = intVal.ToString();
    }

这两种方法都不完美,但我认为第二种方法已经足够接近了。

附加说明:以下示例展示了使用后期绑定类的上述技巧:

public void TestMethod1()
{
    var assembly = System.Reflection.Assembly.GetExecutingAssembly();
    Type t = assembly.GetType("FileHelpers.Tests.CustomersFixedWithNumericId");
    FileHelperEngine engine = new FileHelperEngine(t);

    string path = @"pathtofile\BadCustomersFixedNumericId.txt";

    engine.AfterReadRecord += new Events.AfterReadHandler<object>(engine_AfterReadRecord);
    var res = engine.ReadFile(path);
}

void engine_AfterReadRecord(EngineBase engine, Events.AfterReadEventArgs<object> e)
{
    // validation here
}

谢谢,这看起来很合理,我会试一下。我很惊讶我没有收到你回答这个问题的通知,有点奇怪! - Breadtruck
好的,请尝试将事件声明中的“CustomersFixedWithNumericId”替换为上面两个代码块中的“object”。虽然事件处理程序现在无法引用“e.Record.CustomerID”,因为e.Record现在只是一个对象,但它仍将运行。不过这开始感觉相当脆弱了 - 我认为我会开始寻找一种方法来将所有类型特定的处理强制转移到动态程序集中,但这有点超出了这个问题的范围。 - D. Lambert
答案已编辑。这可能可行,但我不建议这种方法。正如我所说,我认为应该找到一种方法将验证推入汇编语言中,并以让知道该记录定义的汇编语言处理它的方式来处理它。 - D. Lambert
是的,这是一个让你开始变得复杂的地方,因为你要使一切都是后期绑定。你必须反射记录上的属性才能访问它们,而且由于你甚至需要将int字段定义为字符串,你需要其他指示器来显示你想要进行int验证的字段——可能是自定义属性。这样做很快就会让你深入到草丛中去。 - D. Lambert
那么,也许对我来说最好的做法是修改生成错误的文件制作程序源代码,并自己加入修复。我只是认为框架中已经有内置的处理方式了。你觉得呢? - Breadtruck
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接