【问题标题】:Using closedXML C# library, How can I figure out what data is causing this error when trying to save使用 closedXML C# 库,如何在尝试保存时找出导致此错误的数据
【发布时间】:2013-11-20 17:44:10
【问题描述】:

我有一个使用 ClosedXML 导出到 Excel 的 C# 应用程序。它工作得很好,但是当我点击时遇到了一个问题:

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

我得到一个例外:

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

它绝对与数据相关,因为我查看某些数据它工作正常,但其他数据会导致此问题。

我怎样才能确定是哪个字符导致了问题?另外,一旦我弄清楚了,找到这个字符在我的数据中的位置的最佳方法是什么?

【问题讨论】:

  • 根据:web.cs.mun.ca/~michael/c/ascii-table.html 您正在搜索“+”,这在 excel 中可能有问题
  • @Clueless - 我检查过,我的数据中没有任何 +
  • 我相信 0x0B 是垂直制表符。
  • @VincentTan - 关于如何在我的数据中找到它的任何建议?
  • 你能发布完整的堆栈跟踪吗?

标签: c# excel closedxml


【解决方案1】:

由于您放入 ClosedXML 表的数据/字符串中有无效字符,因此您必须找到它们并将它们取出。

最简单的解决方案是添加

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

到你所有的字符串去掉垂直制表符并用空格替换它们。

【讨论】:

  • 换行符不是更适合替换垂直制表符吗?我相信 MS Word 使用垂直制表符作为行分隔符(和 \n 作为段落分隔符)。
  • 当然也可以。然后代码将是.Replace((0x0B).ToString(), Environment.Newline)
  • 是否有另一种方法来检测和替换所有无效字符(而不仅仅是这个)
  • 看看这个question,尤其是这个answer
  • @leora 删除(或者至少是检测)应该在库内完成,而不是在库外。必须从数据中去除无效的 XML 字符只是解决库中代码问题的一种解决方法。
【解决方案2】:

由于 ClosedXML 是一个开源项目,跟踪错误的最简单方法是从 source * 构建它,然后在调试模式下针对库运行您的代码。

看到完整的堆栈跟踪后,您应该能够确定错误的来源。很有可能这是 ClosedXML 项目使用 Microsoft XML 库的方式中的一个错误,因为您提到的错误是由 ClosedXML 项目之外的库报告的。


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

【讨论】:

    【解决方案3】:

    由于 ClosedXML 不会阻止您在值中使用 0x0B 字符,因此您要么必须自己清理它的数据(如@Raidri 所建议的那样),要么您可以强制和异常,或者进行字符串替换设置值时。我在下面创建了一个示例程序,它使用Castle's Dynamic Proxy 来包装IXLWorksheetIXLCell 接口。首先,我们代理IXLWorksheet 值(如下例所示通过添加新工作表或通过索引现有工作表返回)。这需要通过方法调用手动完成;从那时起,其他一切都已建立。访问单元格时(通过Cell 方法或ActiveCell 属性)返回代理IXLCell 值,该值检查通过Value 属性和SetValue 方法设置的数据。根据 cmets,检查在 ValidateMethodInterceptor 中完成。如果您愿意,可以将整个机制留在您的代码库中,并通过Program.Proxy 方法中的开关打开/关闭。

    作为另一种选择,包EPPlus(具有与 ClosedXML 类似的功能)在遇到 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      • 1970-01-01
      • 1970-01-01
      • 2017-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多