如何在C#中处理错误和调试条码操作

This article was translated from English: Does it need improvement?
Translated
View the article in English

条形码处理流程可能会悄无声息地失败,结果为零通常会被误认为是"未检测到条形码"。然而,诸如文件损坏、受密码保护的 PDF 文件或格式不匹配等问题都可能是造成这种情况的原因。 实施适当的日志记录和结构化的错误处理可以发现这些故障并提供可操作的诊断信息。

IronBarcode在IronBarCode.Exceptions 命名空间中提供类型化的异常层次结构、内置的日志记录 API 和详细的 BarcodeResult 属性。 这些属性包括检测到的格式、解码值、页码以及每次成功解码的坐标。

本指南解释了如何捕获和解释类型化异常、从失败的读取中提取诊断上下文、启用结构化日志记录以及隔离批量操作期间的故障。

快速入门:处理条码错误并启用诊断

将读/写调用包装在针对IronBarcode类型异常的try-catch块中,以显现可操作的错误信息,而不是静默失败。

  1. 使用 NuGet 包管理器安装 https://www.nuget.org/packages/BarCode

    PM > Install-Package BarCode
  2. 复制并运行这段代码。

    using IronBarCode;
    using IronBarCode.Exceptions;
    
    try
    {
        BarcodeResults results = BarcodeReader.Read("label.pdf");
        Console.WriteLine($"Found {results.Count} barcode(s)");
    }
    catch (IronBarCodeFileException ex)
    {
        Console.Error.WriteLine($"File error: {ex.Message}");
    }
  3. 部署到您的生产环境中进行测试

    通过免费试用立即在您的项目中开始使用IronBarcode

    arrow pointer

如何捕获和解析IronBarcode异常?

从最具体到最一般,捕获IronBarcode异常。 先处理可操作的异常,例如文件错误、PDF 密码错误和编码错误,然后再处理基本类型异常。 IronBarcode 的.Exceptions 命名空间定义了 11 种异常类型,每种类型对应一种特定的故障模式:

IronBarcode异常类型——原因和推荐修复方法
异常类型触发推荐修复
IronBarCodeFileException文件已损坏、被锁定或为不支持的图像格式。验证文件是否为受支持的图像格式且未被锁定;同时,对于缺失的文件,单独捕获FileNotFoundException
IronBarCodePdfPasswordExceptionPDF受密码保护或加密通过PdfBarcodeReaderOptions提供密码,或跳过文件并记录
IronBarCodeEncodingException在生成条码时发生的通用编码故障验证输入数据符合目标BarcodeWriterEncoding约束
IronBarCodeContentTooLongEncodingException值超过所选符号的字符限制截断数据或切换到更高容量格式(QR, DataMatrix)
IronBarCodeFormatOnlyAcceptsNumericValuesEncodingException为仅数字格式(EAN, UPC)传递了非数字字符清理输入或转换为字母数字格式(Code128, Code39)
IronBarCodeUnsupportedRendererEncodingExceptionIronBarcode无法写入选定的BarcodeEncoding使用BarcodeWriterEncoding枚举而不是BarcodeEncoding
IronBarCodeParsingException解析过程中结构化数据(GS1-128)验证失败在解析前用Code128GS1Parser.IsValid()验证GS1结构
IronBarCodeNativeException本地互操作层错误(缺少DLL,平台不兼容)验证是否安装了平台特定的NuGet包(BarCode.Linux, BarCode.macOS)
IronBarCodeConfidenceThresholdException无效的置信度阈值参数传递给读取器选项确保ConfidenceThreshold介于0.0与1.0之间
IronBarCodeUnsupportedException当前上下文中不支持的操作检查变更日志以获取您版本中功能的可用性
IronBarCodeException基础类型——捕获上述未匹配到的任何IronBarcode特定错误记录完整的异常详情并加以调查

使用带有 when 子句的异常过滤器来路由重叠的异常类型,而无需深度嵌套。 缺少文件时会抛出标准的 System.IO.FileNotFoundException 错误,而不是 IronBarCodeFileException 错误,因此需要为此情况添加单独的 catch 块:

输入

Code128 条形码编码发票号码(成功路径)和仓库标签条形码表示缺失 PDF 的内容(失败路径)。

Code128 条形码编码 INV-2024-7829 用作扫描发票输入
Code128 barcode representing the content of the missing warehouse-labels.pdf failure path input
:path=/static-assets/barcode/content-code-examples/how-to/detailed-error-messages/exception-hierarchy.cs
using IronBarCode;
using IronBarCode.Exceptions;

// Success path: valid file present on disk
string filePath = "scanned-invoice.png";
// Failure path: file does not exist → caught by FileNotFoundException below
// string filePath = "warehouse-labels.pdf";

try
{
    BarcodeResults results = BarcodeReader.Read(filePath);
    foreach (BarcodeResult result in results)
    {
        // Print the detected symbology and decoded value for each barcode found
        Console.WriteLine($"[{result.BarcodeType}] {result.Value}");
    }
}
catch (IronBarCodePdfPasswordException ex)
{
    // PDF is encrypted — supply the password via PdfBarcodeReaderOptions before retrying
    Console.Error.WriteLine($"PDF requires password: {filePath} — {ex.Message}");
}
catch (IronBarCodeFileException ex)
{
    // File is present but corrupted, locked, or in an unsupported format
    Console.Error.WriteLine($"Cannot read file: {filePath} — {ex.Message}");
}
catch (FileNotFoundException ex)
{
    // Missing files throw FileNotFoundException, not IronBarCodeFileException
    Console.Error.WriteLine($"File not found: {filePath} — {ex.Message}");
}
catch (IronBarCodeNativeException ex) when (ex.Message.Contains("DLL"))
{
    // The when filter routes only missing-DLL errors here; other native exceptions
    // fall through to the IronBarCodeException block below
    Console.Error.WriteLine($"Missing native dependency: {ex.Message}");
}
catch (IronBarCodeException ex)
{
    // Base catch for any IronBarcode-specific error not matched by the blocks above
    Console.Error.WriteLine($"IronBarcode error: {ex.GetType().Name} — {ex.Message}");
}
$vbLabelText   $csharpLabel

输出

请注意有效文件解析为解码后的条形码类型和值。

控制台输出显示 Code128 解码成功:[Code128] INV-2024-7829

文件缺失触发 FileNotFoundException,由专用 catch 块路由。

控制台输出显示缺少 warehouse-labels.pdf 文件,并出现 FileNotFoundException 异常。

when (ex.Message.Contains("DLL")) 过滤器对 IronBarCodeNativeException 进行定向,将缺少依赖项错误定向到特定的处理程序,而不影响其他原生异常。 这种方法在 Docker 部署中尤其有用,因为 Docker 部署中可能缺少特定于平台的软件包。

当许可证密钥无效或缺失时,会单独抛出 IronSoftware.Exceptions.LicensingException 错误。 在应用程序启动时捕获此异常,而不是在单个读取或写入调用周围捕获。


如何从读取失败的数据中提取诊断详情?

读取操作返回零结果也不属于例外情况; 它生成一个空的 BarcodeResults 集合。 通过检查输入参数、配置选项和返回的任何部分结果来获取诊断上下文。

BarcodeResult 对象提供了对事后分析有用的属性,包括 PageNumberPoints(角坐标)。 如果结果存在但出乎意料,请先检查 BarcodeType 是否符合预期格式,并验证 PageNumber

输入

Code128 条形码编码发票号码,使用 ExpectBarcodeTypes 读取 Code128QRCode,以及 ReadingSpeed.Detailed 进行彻底扫描。

Code128 条形码编码 INV-2024-7829 用作扫描发票输入
:path=/static-assets/barcode/content-code-examples/how-to/detailed-error-messages/diagnostic-logging.cs
using IronBarCode;

string filePath = "scanned-invoice.png";

// Configure the reader to narrow the search to specific symbologies and use
// a thorough scan pass — narrows false positives and improves decode accuracy
var options = new BarcodeReaderOptions
{
    ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode, // limit scan to known formats
    Speed = ReadingSpeed.Detailed,      // slower but more thorough — use ExtremeDetail for damaged images
    ExpectMultipleBarcodes = true       // scan the full image rather than stopping at the first match
};

BarcodeResults results = BarcodeReader.Read(filePath, options);

// An empty result is not an exception — it means no barcode matched the configured options
if (results == null || results.Count == 0)
{
    // Log the configured options alongside the warning so the cause is immediately actionable
    Console.Error.WriteLine($"[WARN] No barcodes found in: {filePath}");
    Console.Error.WriteLine($"  ExpectedTypes: {options.ExpectBarcodeTypes}");
    Console.Error.WriteLine($"  Speed: {options.Speed}");
    Console.Error.WriteLine($"  Action: Retry with ReadingSpeed.ExtremeDetail or broaden ExpectBarcodeTypes");
}
else
{
    foreach (BarcodeResult result in results)
    {
        // Points contains the four corner coordinates of the barcode in the image;
        // use the first corner as a representative position indicator
        string pos = result.Points.Length > 0 ? $"{result.Points[0].X:F0},{result.Points[0].Y:F0}" : "N/A";
        Console.WriteLine($"[{result.BarcodeType}] {result.Value} "
            + $"(Page: {result.PageNumber}, Position: {pos})");
    }
}
$vbLabelText   $csharpLabel

输出

当代码为 CODE-2707 的条形码与图像中的条形码匹配时,读取操作会返回条形码的类型、值、页码和位置。

控制台输出显示 Code128 解码成功,并显示了页码和位置坐标。

如果 ExpectBarcodeTypes 不包含实际的符号体系,则读取操作返回空结果。 [WARN] 块记录配置的类型、读取速度以及建议的下一步操作。

控制台输出显示 [警告] 未找到条形码,ExpectBarcodeTypes 设置为 Code39,但对应的是 Code128 图像

诊断过程中会出现两种常见模式。 如果 ExpectBarcodeTypes 设置较窄,则结果为空通常意味着条形码使用了不同的符号体系; 扩展到 BarcodeEncoding.All 可以确认这一点。 解码结果异常通常表明图像质量较差。

应用图像滤镜并以较慢的读取速度重试通常可以解决这些问题。 您还可以切换 RemoveFalsePositive 选项,以消除噪声背景中的虚假读取。

如何启用条形码操作的详细日志记录?

IronBarcode通过 IronSoftware.Logger 公开了一个内置的日志记录 API。 在进行任何条形码操作之前,设置日志记录模式和文件路径,以捕获读写管道的内部诊断输出。

输入

启用详细日志记录时,使用 Code128 条形码 TIFF 图像作为读取目标。

Code128 条形码编码 PROB-SCAN-999 用作日志记录示例中的问题扫描输入
:path=/static-assets/barcode/content-code-examples/how-to/detailed-error-messages/enable-logging.cs
using IronBarCode;

// Enable IronBarcode's built-in logging — set BEFORE any read/write calls
// LoggingModes.All writes both debug output and file-level diagnostics
IronSoftware.Logger.LoggingMode = IronSoftware.Logger.LoggingModes.All;
IronSoftware.Logger.LogFilePath = "ironbarcode-debug.log"; // path is relative to the working directory

// All subsequent operations will write internal processing steps to the log file:
// image pre-processing stages, format detection attempts, and native interop calls
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Detailed,
    ExpectBarcodeTypes = BarcodeEncoding.All  // scan for every supported symbology
};

BarcodeResults results = BarcodeReader.Read("problem-scan.tiff", options);
Console.WriteLine($"Read complete. Results: {results.Count}. See ironbarcode-debug.log for details.");
$vbLabelText   $csharpLabel

LoggingModes.All 同时捕获调试输出和文件级日志记录。 日志文件记录内部处理步骤,例如图像预处理阶段、格式检测尝试和本地互操作调用,这些步骤无法通过公共 API 查看。

对于使用结构化日志框架(Serilog、NLog、Microsoft.Extensions.Logging)的生产流水线,将IronBarcode操作封装在中间件层中,会在内置日志文件之外添加结构化的 JSON 条目。内置日志记录器会写入纯文本诊断信息,这些信息有助于支持升级; 结构化包装器为可观测性堆栈提供可查询字段。

:path=/static-assets/barcode/content-code-examples/how-to/detailed-error-messages/structured-wrapper.cs
using IronBarCode;
using System.Diagnostics;

// Lightweight wrapper that adds structured JSON observability to every read call.
// Call this in place of BarcodeReader.Read wherever elapsed-time and status logging is needed.
BarcodeResults ReadWithDiagnostics(string filePath, BarcodeReaderOptions options)
{
    var sw = Stopwatch.StartNew(); // start timing before the read so setup overhead is included
    try
    {
        BarcodeResults results = BarcodeReader.Read(filePath, options);
        sw.Stop();
        // Emit a structured success entry to stdout — pipe to Fluentd, Datadog, or CloudWatch
        Console.WriteLine($"{{\"file\":\"{filePath}\",\"status\":\"ok\","
            + $"\"count\":{results.Count},\"elapsed_ms\":{sw.ElapsedMilliseconds}}}");
        return results;
    }
    catch (Exception ex)
    {
        sw.Stop();
        // Emit a structured error entry to stderr with exception type, message, and elapsed time
        Console.Error.WriteLine($"{{\"file\":\"{filePath}\",\"status\":\"error\","
            + $"\"exception\":\"{ex.GetType().Name}\",\"message\":\"{ex.Message}\","
            + $"\"elapsed_ms\":{sw.ElapsedMilliseconds}}}");
        throw; // rethrow so the caller's catch blocks still handle the exception normally
    }
}
$vbLabelText   $csharpLabel

结构化输出可直接与日志聚合工具集成。 将 stdout 管道传输到容器化部署中的 Fluentd、Datadog 或 CloudWatch。 经过时间字段可以突出显示性能下降情况,防止其演变为服务级别协议 (SLA) 违规。

输出

控制台输出显示条形码读取成功(已启用详细日志记录),并显示了日志文件路径。

如何调试批量条形码处理?

通过将每个读取操作隔离到其自身的 try-catch 块中来处理多个文件,记录每个文件的结果,并生成汇总摘要。 即使出现故障,管道也会继续运行,而不是在遇到第一个错误时停止。

输入

来自 scans/ 批处理目录的五个 Code128 条形码图像中的四个。 第五个文件(scan-05-broken.png)包含无效字节,会触发文件异常。

Code128 barcode encoding ITEM-SQ-001

第一批 — 扫描 1

Code128 barcode encoding ITEM-SQ-002

第一批 — 扫描 2

Code128 barcode encoding ITEM-SQ-003

第一批 — 扫描 3

Code128 barcode encoding ITEM-SQ-004

第一批 — 扫描 4

:path=/static-assets/barcode/content-code-examples/how-to/detailed-error-messages/batch-processing.cs
using IronBarCode;
using IronBarCode.Exceptions;
using System.Diagnostics;

// Enable built-in logging for the entire batch run so internal processing steps
// are captured in the log file alongside the per-file console output
IronSoftware.Logger.LoggingMode = IronSoftware.Logger.LoggingModes.All;
IronSoftware.Logger.LogFilePath = "batch-run.log";

// Collect all files in the directory — SearchOption.TopDirectoryOnly skips subdirectories
string[] files = Directory.GetFiles("scans/", "*.*", SearchOption.TopDirectoryOnly);

var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,                                    // balances throughput vs accuracy
    ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode, // limit to known formats
    ExpectMultipleBarcodes = true                                     // scan each file fully
};

// Three outcome counters: success (decoded), empty (read OK but no barcode found), fail (exception)
int successCount = 0;
int failCount = 0;
int emptyCount = 0;
var errors = new List<(string File, string Error)>(); // per-file error context for root cause analysis
var sw = Stopwatch.StartNew();

foreach (string file in files)
{
    try
    {
        BarcodeResults results = BarcodeReader.Read(file, options);

        // Empty result is not an exception — the file was read but contained no matching barcode
        if (results == null || results.Count == 0)
        {
            emptyCount++;
            errors.Add((file, "No barcodes detected")); // record so caller can adjust options
            continue;
        }

        foreach (BarcodeResult result in results)
        {
            Console.WriteLine($"{Path.GetFileName(file)} | {result.BarcodeType} | {result.Value}");
        }
        successCount++;
    }
    catch (IronBarCodePdfPasswordException)
    {
        // PDF is password-protected — supply password via PdfBarcodeReaderOptions to recover
        failCount++;
        errors.Add((file, "Password-protected PDF"));
    }
    catch (IronBarCodeFileException ex)
    {
        // File is corrupted, locked, or in an unsupported image format
        failCount++;
        errors.Add((file, $"File error: {ex.Message}"));
    }
    catch (FileNotFoundException ex)
    {
        // File was in the directory listing but deleted before the read completed (race condition)
        failCount++;
        errors.Add((file, $"File not found: {ex.Message}"));
    }
    catch (IronBarCodeException ex)
    {
        // Catch-all for any other IronBarcode-specific errors not handled above
        failCount++;
        errors.Add((file, $"{ex.GetType().Name}: {ex.Message}"));
    }
    catch (Exception ex)
    {
        // Unexpected non-IronBarcode error — log the full type for investigation
        failCount++;
        errors.Add((file, $"Unexpected: {ex.GetType().Name}: {ex.Message}"));
    }
}

sw.Stop();

// Summary report — parse failCount > 0 in CI/CD to set a non-zero exit code
Console.WriteLine("\n--- Batch Summary ---");
Console.WriteLine($"Total files:    {files.Length}");
Console.WriteLine($"Success:        {successCount}");
Console.WriteLine($"Empty reads:    {emptyCount}");
Console.WriteLine($"Failures:       {failCount}");
Console.WriteLine($"Elapsed:        {sw.Elapsed.TotalSeconds:F1}s");

if (errors.Any())
{
    Console.WriteLine("\n--- Error Details ---");
    foreach (var (errorFile, errorMsg) in errors)
    {
        Console.Error.WriteLine($"  {Path.GetFileName(errorFile)}: {errorMsg}");
    }
}
$vbLabelText   $csharpLabel

输出

控制台输出显示批处理摘要:4 个成功,1 个失败,并包含损坏文件的错误详细信息。

执行过程中,控制台会为每个解码的条形码输出一行信息,随后是包含文件计数、成功次数、空读取次数、失败次数和运行时间的摘要。错误信息会列出对应的文件名和失败原因。

该过程区分三种结果类别:成功(找到并解码条形码)、空(读取文件但未检测到条形码)和失败(抛出异常)。 这种区别很重要,因为空读取和读取失败需要不同的处理方式。 空读取可能需要更广泛的格式设置,而失败通常表明基础架构问题,例如缺少文件、资源被锁定或缺少本地依赖项。

错误列表维护每个文件的上下文,以支持根本原因分析。 在 CI/CD 管道中,解析此输出以设置退出代码(零表示完全成功,非零表示 failCount 大于零)或将错误详细信息转发到警报系统。

为了提高吞吐量,请将 Multithreaded 设置为 true,并调整 MaxParallelThreads 以匹配可用的 CPU 核心,从而启用并行处理。 通过将并行迭代包装在 Parallel.ForEach 中,并使用线程安全的集合来存储错误列表,从而保持每个文件的隔离。


进一步阅读

当管道准备就绪投入生产时,请查看许可选项

常见问题解答

如何使用IronBarcode处理条码操作中的错误?

IronBarcode提供类型化异常和内置日志记录,以有效管理和处理条码操作中的错误,确保您的应用程序平稳运行。

IronBarcode为调试条码问题提供了哪些功能?

IronBarcode包括诊断提取和生产就绪的批量错误隔离,这些功能帮助开发人员高效识别和解决与条码相关的问题。

IronBarcode可以在条码处理过程中记录错误吗?

是的,IronBarcode具有内置的日志记录能力,允许开发人员在条码处理过程中捕获和记录错误细节,方便调试。

IronBarcode中的类型化异常是什么?

IronBarcode中的类型化异常是特定的错误类型,提供详细的条码操作问题信息,使开发人员更容易诊断和解决问题。

IronBarcode如何协助批量错误隔离?

IronBarcode提供生产就绪的批量错误隔离,帮助分离有问题的条码操作与成功的操作,简化批量处理中的错误管理。

IronBarcode是否有办法从条码操作中提取诊断信息?

是的,IronBarcode提供诊断提取工具,帮助开发人员收集关于条码操作的详细信息,有助于故障排除和错误解决。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

准备开始了吗?
Nuget 下载 2,121,847 | 版本: 2026.3 刚刚发布
Still Scrolling Icon

还在滚动吗?

想快速获得证据? PM > Install-Package BarCode
运行示例 观看您的字符串变成 BarCode。