使用closedXML C#库,试图保存时如何找出导致此错误的数据

我有一个C#应用程序,使用ClosedXML导出到Excel。 它工作正常,但遇到了一个问题,当我打到:

var ms = new MemoryStream(); workbook.SaveAs(ms); 

我得到一个例外:

 ' ', hexadecimal value 0x0B, is an invalid character 

它绝对的数据相关,因为它看起来很好,但其他数据导致这个问题。

我怎样才能找出哪个字符造成的问题? 另外,一旦我明白了,find这个angular色在我的数据中的最佳方式是什么?

由于在放入ClosedXML表单中的数据/string中包含无效字符,因此必须find它们并将其取出。

最简单的解决方法是添加

 .Replace((0x0B).ToString(), " ") 

到所有的string摆脱垂直标签,并用空格replace它们。

由于ClosedXML是一个开源项目,因此跟踪错误的最简单方法是从源代码构build它,然后在debugging模式下针对库运行代码。

一旦你看到完整的堆栈跟踪,你应该能够识别出错的地方。 很有可能这是ClosedXML项目使用Microsoft XML库的一种错误,因为您提到的错误是由ClosedXML项目之外的库报告的。


*我下载了这个项目,并试图build立它。 closedxml-79843.zip包中的所有内容都可以正确构build。

由于ClosedXML并不妨碍你在值中使用0x0B字符,所以你必须自己擦掉你的数据(如@Raidri所build议的),或者你可以强制和exception,或者当值被设置。 我创build了一个示例程序,下面使用Castle的dynamic代理来包装IXLWorksheetIXLCell接口。 首先,我们代理IXLWorksheet值(从下面的例子中添加一个新的工作表,或者索引现有的工作表)。 这需要通过方法调用手动完成; 从此以后的一切都build立起来了。 在访问单元格时(通过Cell方法或ActiveCell属性),返回代理的IXLCell值,通过Value属性和SetValue方法检查正在设置的数据。 根据注释在ValidateMethodInterceptor完成检查。 如果你愿意的话,这整个机制可以留在你的代码库中,并通过Program.Proxy方法中的开关打开/closures。

作为另一种select,包EPPlus (与ClosedXML具有类似的function)在遇到VT字符时不会崩溃。 取而代之的是值_x00B_ 。 也许交换会更有益?

 internal class Program { private static void Main(string[] args) { var stream = new MemoryStream(); using (stream) { using (var workbook = new XLWorkbook()) { using (var worksheet = Proxy(workbook.Worksheets.Add("Sheet 1"))) { worksheet.Cell("A1").Value = "This is a test"; worksheet.Cell("A2").Value = "This \v is a test"; workbook.SaveAs(stream); } } } } public static IXLWorksheet Proxy(IXLWorksheet target) { var generator = new ProxyGenerator(); var options = new ProxyGenerationOptions { Selector = new WorksheetInterceptorSelector() }; return generator.CreateInterfaceProxyWithTarget<IXLWorksheet>(target, options); } } public class WorksheetInterceptorSelector : IInterceptorSelector { private static readonly MethodInfo[] methodsToAdjust; private readonly ProxyCellInterceptor proxyCellInterceptor = new ProxyCellInterceptor(); static WorksheetInterceptorSelector() { methodsToAdjust = typeof(IXLWorksheet).GetMethods() .Where(x => x.Name == "Cell") .Union(new[] { typeof(IXLWorksheet).GetProperty("ActiveCell").GetGetMethod() }) .ToArray(); } #region IInterceptorSelector Members public IInterceptor[] SelectInterceptors(System.Type type, System.Reflection.MethodInfo method, IInterceptor[] interceptors) { if (!methodsToAdjust.Contains(method)) return interceptors; return new IInterceptor[] { proxyCellInterceptor }.Union(interceptors).ToArray(); } #endregion } public class CellInterceptorSelector : IInterceptorSelector { private static readonly MethodInfo[] methodsToAdjust = new[] { typeof(IXLCell).GetMethod("SetValue"), typeof(IXLCell).GetProperty("Value").GetSetMethod() }; private ValidateMethodInterceptor proxyCellInterceptor = new ValidateMethodInterceptor(); #region IInterceptorSelector Members public IInterceptor[] SelectInterceptors(System.Type type, MethodInfo method, IInterceptor[] interceptors) { if (method.IsGenericMethod && method.Name == "SetValue" || methodsToAdjust.Contains(method)) return new IInterceptor[] { proxyCellInterceptor }.Union(interceptors).ToArray(); return interceptors; } #endregion } public class ProxyCellInterceptor : IInterceptor { #region IInterceptor Members public void Intercept(IInvocation invocation) { invocation.Proceed(); //Wrap the return value invocation.ReturnValue = Proxy((IXLCell)invocation.ReturnValue); } #endregion public IXLCell Proxy(IXLCell target) { var generator = new ProxyGenerator(); var options = new ProxyGenerationOptions { Selector = new CellInterceptorSelector() }; return generator.CreateInterfaceProxyWithTarget<IXLCell>(target, options); } } public class ValidateMethodInterceptor : IInterceptor { #region IInterceptor Members public void Intercept(IInvocation invocation) { var value = invocation.Arguments[0]; //Validate the data as it is being set if (value != null && value.ToString().Contains('\v')) { throw new ArgumentException("Value cannot contain vertical tabs!"); } //Alternatively, you could do a string replace: //if (value != null && value.ToString().Contains('\v')) //{ // invocation.Arguments[0] = value.ToString().Replace("\v", Environment.NewLine); //} invocation.Proceed(); } #endregion }