冰蓝科技
|
028-81705109
|
|
微信扫一扫
|

Spire.Cloud 纯前端文档控件

使用 C# 实现字节串和PDF之间的转换

在 C# 开发中,处理 PDF 的字节数组是一种常见需求。开发者常常需要将 PDF 文档存储到数据库、通过 API 传输,或者完全在内存中进行处理而不依赖文件系统。在这些场景下,在 C# 中实现 PDF 与字节数组的互转 就显得尤为重要。

本文将通过 Spire.PDF for .NET 演示具体实现步骤。你将学习如何将字节数组转换为 PDF,如何将 PDF 转换为字节数组,以及如何直接在内存中使用 C# 代码编辑 PDF。

快速导航

为什么在 C# 中要处理 PDF 与字节数组?

使用 byte[] 作为传输格式,可以避免生成临时文件,使代码更适配云环境和容器环境。

  • 数据库存储 (BLOB): 将 PDF 以原始字节形式存储,仅在需要时加载。
  • Web API: 通过 HTTP 发送或接收 PDF,无需磁盘读写。
  • 内存处理: 在流中完成 PDF 的转换或加水印操作。
  • 安全与隔离: 减少文件 I/O,降低临时文件风险。

准备工作: 在运行示例前,请先在项目中安装 Spire.PDF for .NET 的 NuGet 包。

Install-Package Spire.PDF

安装完成后,即可通过 byte[] 或 Stream 加载 PDF,编辑页面,并将结果写回内存或磁盘,无需额外转换器。

在 C# 中将字节数组转换为 PDF

当上游服务(如 API 或消息队列)传递一个代表 PDF 的 byte[] 时,通常需要将其还原为文档,便于进一步处理或保存到磁盘。使用 Spire.PDF for .NET,这个过程可以直接在内存中完成,无需中间临时文件。

应用场景与方法: 从数据库或 API 获取一个 byte[],在内存中构建 PdfDocument,可选地验证一些基础信息,然后保存为 PDF。

using Spire.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // 示例来源:从数据库或 API 获取的字节数组
        byte[] pdfBytes = File.ReadAllBytes("Sample.pdf"); // 请替换为实际数据来源

        // 1) 从字节数组加载 PDF(内存中完成)
        PdfDocument doc = new PdfDocument();
        doc.LoadFromBytes(pdfBytes);

        // 2) (可选)在保存或处理前查看文档信息
        // int pageCount = doc.Pages.Count;

        // 3) 保存为文件
        doc.SaveToFile("Output.pdf");
        doc.Close();
    }
}

下图展示了字节数组到 PDF 的转换流程:

bytes loaded into PdfDocument and saved as PDF in C# with Spire.PDF

代码解析:

  • LoadFromBytes(byte[]) 可直接在内存中初始化 PDF,适合无写入权限的服务环境。
  • 加载完成后可以进行多种操作:验证页面、打码、加盖印章或路由到其他流程。
  • SaveToFile(string) 将文档保存到磁盘,便于后续处理或存储。

在 C# 中将 PDF 转换为字节数组

反向转换时,将 PDF 转换为 byte[] 便于写入数据库、缓存,或通过 HTTP 响应返回文件。Spire.PDF for .NET 支持将 PDF 保存到 MemoryStream,再通过 ToArray() 转换为字节数组。

应用场景与方法: 加载现有 PDF,将其保存到 MemoryStream,再提取 byte[]。这种方式特别适用于 API 返回 PDF 或持久化存储。

using Spire.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // 1) 从磁盘、网络或资源文件加载 PDF
        PdfDocument doc = new PdfDocument();
        doc.LoadFromFile("Input.pdf");

        // 2) 保存到内存流,避免生成临时文件
        byte[] pdfBytes;
        using (var ms = new MemoryStream())
        {
            doc.SaveToStream(ms);
            pdfBytes = ms.ToArray();
        }

        doc.Close();

        // pdfBytes 现在包含完整文档(可直接写入数据库或 API 返回)
        // 示例:return File(pdfBytes, "application/pdf");
    }
}

下图展示了 PDF 转换为字节数组的流程:

PDF loaded into PdfDocument, saved to MemoryStream, then bytes in C#

关键点总结:

  • SaveToStream → ToArray 是在 C# 中获取 PDF 字节的标准方式,无需生成临时文件。
  • 这种方法适合大文件处理,内存使用量仅受限于系统资源。
  • 在 ASP.NET 中尤其实用,可直接返回字节数组给前端或 API 调用方。

直接从字节数组创建和编辑 PDF

更强大的场景是直接在内存中编辑 PDF。你可以从 byte[] 加载 PDF,添加文字或图片、加水印、填写表单,再将结果保存为新的 byte[]。这种无文件管道非常适合微服务。

应用场景与方法: 从字节数组加载 PDF,在第一页添加文字标记,最后输出新的字节数组。

using Spire.Pdf;
using Spire.Pdf.Graphics;
using System.Drawing;
using System.IO;

class Program
{
    static void Main()
    {
        // 来源可以是数据库、API 或文件,这里用 byte[] 表示
        byte[] inputBytes = File.ReadAllBytes("Input.pdf");

        // 1) 内存加载 PDF
        var doc = new PdfDocument();
        doc.LoadFromBytes(inputBytes);

        // 2) 编辑:在第一页写入一个小标记
        PdfPageBase page = doc.Pages[0];
        page.Canvas.DrawString(
            "编辑后的PDF文档",
            new PdfTrueTypeFont(new Font("HarmonyOS Sans SC", 26f), true),
            PdfBrushes.DarkBlue,
            new PointF(100, page.Size.Height - 100)
        );

        // 3) 保存为新的字节数组
        byte[] editedBytes;
        using (var ms = new MemoryStream())
        {
            doc.SaveToStream(ms);
            editedBytes = ms.ToArray();
        }

        doc.Close();

        // editedBytes 可持久化存储或由 API 返回
    }
}

下图展示了编辑后的 PDF 页面:

Edited PDF page with insrted text using C# in bytes

要点说明:

  • 同样的方式可应用于 文本、图片、水印、批注、表单字段 等编辑操作。
  • 建议保持操作幂等(如检查是否已加盖印章),避免重复处理。
  • 在 ASP.NET 中非常适合 即时加印 或 条件脱敏,再返回给调用方。

如果你想学习如何从零创建 PDF,可以参考我们的文章:在 C# 中创建 PDF 文档。

使用 Spire.PDF for .NET 的优势

下表总结了该 API 在字节数组处理中的优势:

需求点 Spire.PDF for .NET 的优势
I/O 灵活性 同一个 PdfDocument API 支持从文件路径、Stream 或 byte[] 加载与保存
内存编辑 可绘制文本/图片、管理批注/表单、添加水印等,无需临时文件
服务友好 轻松集成到 ASP.NET 接口和后台任务
处理真实文档 支持多页 PDF,可通过流控制内存消耗
代码简洁 避免手动字节操作和复杂互操作,简化实现

总结

本文演示了如何在 C# 中 将字节数组转换为 PDF、如何 将 PDF 转换为字节数组,以及如何 直接在内存中编辑 PDF。通过流和字节数组操作,可以让 API 设计更简洁、响应更高效,同时兼顾数据库和云环境的适配性。Spire.PDF for .NET 提供了一套一致的无文件化工作流,既适合快速转换,也能扩展为完整的内存文档处理。

如果你想在无功能限制的情况下体验这些特性,可以申请 30 天免费临时授权。或者,你也可以试用 Free Spire.PDF for .NET,适合轻量级 PDF 任务。

常见问题

可以在不保存到磁盘的情况下,通过字节数组创建 PDF 吗?

可以。使用 LoadFromBytes 从 byte[] 加载 PDF,然后保存到 MemoryStream 或直接在 API 中返回,无需落盘。

如何在 C# 中将 PDF 转换为字节数组以便存入数据库?

使用 PdfDocument.SaveToStream 方法,并调用 MemoryStream.ToArray() 获取字节数组,再存储为 BLOB 或传递给其他服务。

能否编辑仅存在于字节数组中的 PDF?

完全可以。先通过字节数组加载 PDF,再进行文字、图片、水印、批注或表单填写等编辑,最后保存为新的 byte[]。

有哪些性能与可靠性建议?

及时释放流、在合适的场景重用缓冲区、每个操作/线程单独创建 PdfDocument。对于大文件,建议使用流式 I/O 控制内存使用,保证可预测性。

Spire.Presentation for .NET 10.8.2 现已发布, 该版本更新了 .NET 6.0 和 .NET Core 2.0 框架下的依赖项,并修复了在将 PPTX 转换为 PDF 时出现的一系列问题。更多详细信息如下所示。

更新依赖项::

问题修复:


获取 Spire.Presentation 10.8.2,请点击:

https://www.e-iceblue.cn/Downloads/Spire-Presentation-NET.html

Spire.PDF for Java 11.8.3 现已正式发布。该版本优化了 PDF 转 OFD 的内存消耗,并且还修复了一个在转换 SVG 到 PDF 文件时遇到的问题。详情请查阅以下内容。

优化:

问题修复:


获取 Spire.PDF for Java 11.8.3 请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-JAVA.html

Python添加水印到PDF

水印技术是保护文档安全、声明所有权及防止未经授权复制的关键手段。无论是分发草稿还是为最终交付成果添加品牌标识,使用水印都能有效保护您的内容。本教程将指导您如何使用 Spire.PDF for Python 在 Python 中为 PDF 文件添加水印 。

我们将逐步演示如何插入文字水印与图片水印、调整透明度与定位,并解决常见问题——所有步骤均配有清晰且注释完善的代码示例。

Python PDF 水印处理库

Spire.PDF for Python 是一款功能强大的 PDF 处理库,特别针对水印功能提供以下特性:

  • 精准定位 :支持高精度水印定位与旋转
  • 透明度调节 :灵活的透明度控制选项
  • 多格式支持 :可添加文字或图片水印
  • 灵活应用 :支持单页或整份文档的水印添加
  • 无损质量 :保持原始 PDF 文件质量

开始前请确保已通过以下命令安装库:

pip install spire.pdf

添加文字水印到 PDF

以下代码演示如何为 PDF 每页添加倾斜的"禁止复制"文字水印,包含字号、颜色、位置、旋转角度及透明度的专业级设置:

from spire.pdf import *
from spire.pdf.common import *
import math

# 创建PdfDocument类的对象
doc = PdfDocument()

# 从指定路径加载PDF文档
doc.LoadFromFile("C:\\Users\\Administrator\\Desktop\\Input.pdf")

# 为水印字体创建PdfTrueTypeFont类的对象
font = PdfTrueTypeFont("黑体", 48.0, 0, True)

# 指定水印文本
text = "禁 止 复 制"

# 测量文本的尺寸以确保正确定位
text_width = font.MeasureString(text).Width
text_height = font.MeasureString(text).Height

# 循环遍历文档中的每一页
for i in range(doc.Pages.Count):

    # 获取当前页面
    page = doc.Pages.get_Item(i)
    
    # 保存当前画布状态
    state = page.Canvas.Save()
 
    # 计算页面的中心坐标
    x = page.Canvas.Size.Width  / 2
    y = page.Canvas.Size.Height / 2

    # 将坐标系平移到中心,使页面的中心成为原点(0, 0)
    page.Canvas.TranslateTransform(x, y)
    
    # 将画布逆时针旋转45度以显示水印
    page.Canvas.RotateTransform(-45.0)

    # 设置水印的透明度
    page.Canvas.SetTransparency(0.4)
    
    # 使用负偏移量在中心位置绘制水印文本
    page.Canvas.DrawString(text, font, PdfBrushes.get_Blue(), PointF(-text_width / 2, -text_height / 2))
    
    # 恢复画布状态,以防止变换影响后续绘图
    page.Canvas.Restore(state)

# 将修改后的文档保存到新的PDF文件
doc.SaveToFile("output/TextWatermark.pdf")

# 释放资源
doc.Dispose()

代码解析:

  1. 加载 PDF 文档 :通过 PdfDocument 类从指定路径加载待处理的 PDF 文件。
  2. 配置水印文本 :设置水印文字内容("禁 止 复 制"),并指定字体(黑体,48磅字号),同时测量文本尺寸以实现精准定位。
  3. 应用图形变换 :针对每个页面执行以下操作:
    • 将坐标系原点移至页面中心
    • 画布逆时针旋转45度
    • 设置水印透明度为40%
  4. 绘制水印 :在坐标(-text_width/2, -text_height/2)处绘制文本,该计算确保无论画布如何旋转,文字始终以页面中心为基准对称分布。
  5. 保存文档 :将处理后的文档另存为新 PDF 文件。

效果图:

Python添加文本水印到PDF

添加图片水印到 PDF

以下代码演示如何为PDF每一页添加半透明图片水印,确保精准定位并呈现专业视觉效果。

from spire.pdf import *
from spire.pdf.common import *

# 创建PdfDocument类的对象
doc = PdfDocument()

# 从指定路径加载PDF文档
doc.LoadFromFile("C:\\Users\\Administrator\\Desktop\\Input.pdf")

# 从指定路径加载水印图像
image = PdfImage.FromFile("C:\\Users\\Administrator\\Desktop\\logo.png")

# 获取加载的图像的宽度和高度以进行定位
imageWidth = float(image.Width)
imageHeight = float(image.Height)

# 循环遍历文档中的每一页以应用水印
for i in range(doc.Pages.Count):
    # 获取当前页面
    page = doc.Pages.get_Item(i)

    # 将水印的透明度设置为50%
    page.Canvas.SetTransparency(0.5)

    # 获取当前页面的尺寸
    pageWidth = page.ActualSize.Width
    pageHeight = page.ActualSize.Height

    # 计算x和y坐标以将图像居中放置在页面上
    x = (pageWidth - imageWidth) / 2
    y = (pageHeight - imageHeight) / 2

    # 在计算出的中心位置绘制图像
    page.Canvas.DrawImage(image, x, y, imageWidth, imageHeight)

# 将修改后的文档保存到新的PDF文件
doc.SaveToFile("output/ImageWatermark.pdf")

# 释放资源
doc.Dispose()

代码解析:

  1. 加载 PDF 文档 :通过PdfDocument类从指定路径加载需要添加水印的PDF文件。
  2. 配置水印图片: 从指定路径加载水印图片文件,并获取图片尺寸参数以实现精确定位。
  3. 应用图像处理 :对每个页面执行以下操作:
    • 设置水印透明度为50%
    • 计算页面中心坐标作为水印位置基准
  4. 绘制水印图像 :根据计算出的中心坐标绘制水印图片,确保在每页居中显示。
  5. 保存文档 :将添加水印后的文档另存为新的PDF文件。

效果图:

Python添加图片水印到PDF

除了水印之外,您还可以为 PDF 添加图章。与水印固定位置不同,图章可以自由移动或删除,为文档批注提供了更大的灵活性。

常见问题排查

  1. 水印未显示:
    • 检查文件路径是否正确
    • 确认透明度未设置为0(完全透明)
    • 确保水印坐标位于页面边界内
  2. 质量问题:
    • 文字水印建议使用更高质量的字体
    • 图片水印需确保足够的分辨率
  3. 旋转异常:
    • 注意旋转是围绕当前原点进行的
    • 变换顺序很重要(先平移后旋转)

总结

借助 Spire.PDF for Python 库,为 PDF 文档添加水印既简单便捷又功能强大。您既可以批量添加醒目的"机密"警示水印,也能嵌入品牌 Logo 作为优雅的背景标识。该库支持灵活的坐标定位、透明度调节、旋转等高级功能,让您能够根据文档类型和使用场景,轻松打造专业级的水印解决方案。

问答集锦

Q1. 能否在同一个PDF中同时添加文字和图片水印?

可以,您只需在遍历PDF页面的循环中结合使用两种水印添加方法即可。

Q2. 如何旋转图片水印?

与文字水印示例类似,在绘制图片前使用 Canvas.RotateTransform( 角度) 方法即可实现旋转。

Q3. Spire.PDF是否支持透明PNG作为水印?

支持。当使用PNG图片作为水印时,Spire.PDF会保留其原有的透明度。

Q4. 能否为不同页面添加不同的水印?

完全可以。您可以在页面循环中添加条件判断逻辑,根据页码或其他标准为不同页面应用不同的水印。

申请临时License

如果您需要去除生成文档中的评估提示或解除功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。

在 ASP.NET Core 中使用 C# 和 Spire.Barcode 扫描二维码和条码

在现代业务应用中,在 ASP.NET 环境下扫描条码和二维码的需求非常常见。无论是票务验证、支付处理,还是库存管理,集成一个ASP.NET 二维码扫描器或条码读取功能,都能显著提升系统的效率和准确性。

本教程将演示如何使用 Spire.Barcode for .NET 和 C#,在 ASP.NET 中实现完整的条码扫描解决方案。我们将创建一个 ASP.NET Core Web 应用,能够从上传的图片中读取二维码和多种条码格式,识别准确,并可方便地集成到现有项目中。

教程概览

1. 项目创建

步骤 1:创建项目

创建一个新的 ASP.NET Core Razor Pages 项目,作为扫描功能的基础。可通过以下命令创建新项目,也可在 Visual Studio 中手动配置:

dotnet new webapp -n QrBarcodeScanner
cd QrBarcodeScanner

步骤 2:安装 Spire.Barcode for .NET

安装 Spire.Barcode for .NET NuGet 包。该组件支持解码多种条码类型,并提供简单易用的 API。可在 NuGet 包管理器中搜索或使用以下命令安装:

dotnet add package Spire.Barcode

Spire.Barcode for .NET 内置支持二维码和多种条码格式,如 Code128、EAN-13 和 Code39,无需额外的图像处理库即可集成到 ASP.NET 项目。更多支持的条码类型,请参考 BarCodeType API 文档。

对于小型项目,也可使用 Free Spire.Barcode for .NET。

2. 在 ASP.NET 中实现二维码与条码扫描功能

二维码和条码的扫描功能主要包括两部分:

  1. 处理和解码上传图片的后端逻辑。
  2. 网页界面,用于上传扫描图片并显示结果。

我们先实现后端,确保扫描流程正确,然后再连接一个简洁的 Razor Page 前端,从而构建一个完整的二维码与条码扫描解决方案。

后端:使用 Spire.Barcode 实现二维码和条码扫描逻辑

后端代码将上传的文件读入内存,并使用 Spire.Barcode 进行扫描,可通过内存流或文件路径处理。扫描结果会返回给前端。此实现支持二维码及其他条码类型,无需针对格式编写额外逻辑。

Index.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Spire.Barcode;

public class IndexModel : PageModel
{
    [BindProperty]
    public IFormFile Upload { get; set; }  // 上传的文件

    public string Result { get; set; }     // 扫描结果
    public string UploadedImageBase64 { get; set; } // 用于预览的 Base64 字符串

    public void OnPost()
    {
        if (Upload != null && Upload.Length > 0)
        {
            using (var ms = new MemoryStream())
            {
                // 将上传文件读入内存
                Upload.CopyTo(ms);

                // 转换为 Base64,用于 HTML <img> 显示
                UploadedImageBase64 = "data:" + Upload.ContentType + ";base64," +
                                      Convert.ToBase64String(ms.ToArray());

                // 重置流位置以便扫描
                ms.Position = 0;

                // 扫描二维码或条码
                try
                {
                    string[] scanned = BarcodeScanner.Scan(ms);
                    Result = scanned != null && scanned.Length > 0
                        ? string.Join(", ", scanned)
                        : "未检测到二维码或条码。";
                }
                catch (Exception ex)
                {
                    Result = "扫描过程中出错: " + ex.Message;
                }
            }
        }
    }
}

关键类和方法说明

  • BarcodeScanner:Spire.Barcode 的静态类,用于解码图片中的二维码或条码。
  • BarcodeScanner.Scan(Stream imageStream):从内存流扫描图片,返回解码后的字符串数组,可扫描图片中所有条码。Scan 方法会扫描图像中的所有条码,并返回扫描结果。
  • 可选方法:
    • BarcodeScanner.Scan(string imagePath):从文件路径扫描图片。
    • BarcodeScanner.ScanInfo(string imagePath):返回附加条码信息,如类型、在图片中的位置和储存的数据。

根据应用需求,这些方法可灵活使用。

前端:二维码与条码上传及结果显示界面

下面的页面提供一个简洁的上传表单,用户上传包含二维码或条码的图片后,可显示图片及识别结果,并可一键复制。页面布局保持简洁,实现了在浏览器中快速识别二维码等条码的能力。

Index.cshtml

@page
@model IndexModel
@{
    ViewData["Title"] = "二维码与条码扫描器";
}

<div style="max-width:420px;margin:40px auto;padding:20px;border:1px solid #ccc;border-radius:8px;background:#f9f9f9;">
    <h2>二维码与条码扫描器</h2>
    <form method="post" enctype="multipart/form-data" id="uploadForm">
        <input type="file" name="upload" accept="image/*" required onchange="this.form.submit()" style="margin:10px 0;" />
    </form>

    @if (!string.IsNullOrEmpty(Model.UploadedImageBase64))
    {
        <div style="margin-top:15px;text-align:center;">
            <img src="@Model.UploadedImageBase64" style="width:300px;height:300px;object-fit:contain;border:1px solid #ddd;background:#fff;" />
        </div>
    }

    @if (!string.IsNullOrEmpty(Model.Result))
    {
        <div style="margin-top:15px;padding:10px;background:#e8f5e9;border-radius:6px;">
            <b>扫描结果:</b>
            <p id="scanText">@Model.Result</p>
            <button type="button" onclick="navigator.clipboard.writeText(scanText.innerText)" style="background:#28a745;color:#fff;padding:6px 10px;border:none;border-radius:4px;">复制</button>
        </div>
    }
</div>

下图展示了扫描页面成功识别二维码和 Code128 条码后的效果,结果显示并可一键复制:

ASP.NET Core 二维码与 Code128 条码扫描页面,显示识别结果并支持复制

该 ASP.NET Core 应用可以从上传图片扫描二维码和条码。如需生成二维码或条码,请参考 在 ASP.NET Core 中生成二维码教程。


3. 测试与排错

运行应用后,可用以下图片测试扫描功能:

  • 包含 URL 或纯文本的二维码图片。
  • Code128 或 EAN-13 条形码图片。

若识别失败:

  • 确保图片对比度清晰,畸变较小。
  • 使用分辨率适中的图片(不要过大或像素化)。
  • 测试不同格式,如 JPG、PNG 或 BMP。
  • 避免反光、眩光或光线不足的图片。
  • 当一张图片中有多个条码时,确保条码之间清晰分隔,以提高识别率。

建议维护一个小型二维码和条码样本库,用于修改代码后定期测试。

4. 扩展到其他 .NET 应用

本教程的条码扫描逻辑在不同 .NET 应用类型中使用方式相同,只需提供图片的方式不同。核心解码方法 BarcodeScanner.Scan() 可在以下环境中复用:

  • ASP.NET Core MVC 控制器 或 Web API 接口
  • 桌面应用(如 WinForms 或 WPF)
  • 控制台工具(用于批量处理)

示例:最简 ASP.NET Core Web API 接口 — 接收 HTTP POST 上传的图片,并返回解码结果 JSON:

[ApiController]
[Route("api/[controller]")]
public class ScanController : ControllerBase
{
    [HttpPost]
    public IActionResult Scan(IFormFile file)
    {
        if (file == null) return BadRequest("未上传文件");
        using var ms = new MemoryStream();
        file.CopyTo(ms);
        ms.Position = 0;
        string[] results = BarcodeScanner.Scan(ms);
        return Ok(results);
    }
}

示例:控制台应用 — 扫描本地图片文件并打印解码文本:

string[] result = BarcodeScanner.Scan(@"C:\path\to\image.png");
Console.WriteLine(string.Join(", ", result));

这种灵活性方便开发者快速在新项目中集成二维码和条码扫描,或扩展已有 .NET 应用。

5. 总结

本教程展示了如何在 ASP.NET Core 中使用 Spire.Barcode for .NET,实现完整的二维码和条码扫描解决方案。从上传图片到解码显示结果,流程清晰,适用于多种应用类型。借助此方法,开发者可以快速在电商平台、票务系统、文件验证工具及其他关键业务 Web 应用中集成可靠的扫描功能。

对于更高级的场景,Spire.Barcode for .NET 提供了自定义识别流程、支持多种图片格式和条码类型等功能。申请免费试用以解锁所有高级功能。

立即下载 Spire.Barcode for .NET,开始构建自己的 ASP.NET 条码扫描解决方案。

Spire.Doc for Python 13.8.0 现已正式发布。该版本支持设置图表坐标轴间距,同时修复了获取文本框数量、公式显示、文档对比、自定义属性及内容格式等多个问题。更多详情如下。

新功能:

问题修复:


获取 Spire.Doc for Python 13.8.0 请点击:

https://www.e-iceblue.cn/Downloads/Spire-Doc-Python.html

C# Excel 转 JSON 和 JSON 转 Excel 图文教程

Excel 常用于数据录入、整理和报表展示,而 JSON 则广泛应用于接口通信、前后端数据交互和系统集成。当数据需要在业务人员使用的 Excel 文件与程序使用的 JSON 格式之间流转时,就需要完成两种格式的相互转换。

本文将详细介绍如何使用 C# 和 Spire.XLS for .NET 库实现 Excel 转 JSON 和 JSON 转 Excel。内容涵盖导出整个工作簿、指定工作表和单元格区域为 JSON,自定义 JSON 输出格式,以及扁平或嵌套 JSON 数据写入 Excel 等常见场景,并提供可直接参考的代码示例。

目录

为什么要在 Excel 与 JSON 之间进行转换?

在 .NET 应用程序中,Excel(.xlsx 或 .xls)与 JSON 之间的转换通常用于以下场景:

  • 导入业务数据:将业务人员提交的 Excel 表格转换为后端程序可以处理的数据结构。
  • 对接 API:将 Excel 中的表格数据整理为接口所需的 JSON 请求数据。
  • 前后端数据传输:将服务端数据转换为 JSON,供网页、移动端或 JavaScript 应用使用。
  • 迁移到文档数据库:将表格数据转换为适合 MongoDB、Cosmos DB 等数据库存储的 JSON。
  • 生成 Excel 报表:将接口或业务系统返回的 JSON 数据整理为便于用户查看和分析的 Excel 报表。

开发环境准备与库安装

开始之前,请确保开发环境满足以下要求:

  • Visual Studio(建议使用 2019 或更高版本)
  • .NET 环境: .NET Framework 4.0+、.NET Core 3.1+ 或 .NET 5.0+
  • NuGet 程序包:

安装所需的 NuGet 程序包

方法一:使用 .NET 程序包管理器控制台

在 Visual Studio 中打开项目,然后在“程序包管理器控制台”中执行以下命令:

Install-Package Spire.XLS
Install-Package Newtonsoft.Json

方法二:使用 .NET CLI

在终端环境中进行跨平台开发时,可在项目根目录执行以下命令:

dotnet add package Spire.XLS
dotnet add package Newtonsoft.Json

C# Excel 转 JSON 基础示例

从 Spire.XLS for .NET 15.11.3 版本开始,开发者可以调用 SaveToFile() 方法,直接将 Excel 文件导出为 JSON 文件。这种方式适合转换整个工作簿,并且不需要自定义 JSON 结构的场景。

实现步骤

  1. 创建一个新的 Workbook 对象。
  2. 调用 LoadFromFile() 方法加载 Excel 工作簿。
  3. 调用 SaveToFile() 方法,并将输出格式指定为 FileFormat.Json。

完整代码示例

using System;
using Spire.Xls;

namespace ConvertExcelToJSON
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputFile = @"Sample.xlsx";
            string outputFile = @"output.json";

            try
            {
                // 创建 Workbook 对象
                using (Workbook workbook = new Workbook())
                {
                    // 加载 Excel 文件
                    workbook.LoadFromFile(inputFile);

                    // 将整个工作簿保存为一个 JSON 文件
                    // 此功能需要 Spire.XLS 15.11.3 或更高版本
                    workbook.SaveToFile(outputFile, FileFormat.Json);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"转换过程中发生错误:{ex.Message}");
            }
        }
    }
}

输出的 JSON 文件:

转换后的 JSON 结构与 Excel 的对照关系如下:

  • 工作表名称 → 对应 JSON 最外层对象中的键(Key)。
  • 每个工作表中的数据 → 对应一个数组,数组中的每个对象表示一行数据。
  • 表头行的单元格内容 → 默认作为每个数据对象的字段名称。

C# Excel 转 JSON 输出结果

Excel 转 JSON 自定义设置

直接将整个工作簿保存为 JSON 非常高效,但在一些场景中,需要对转换范围或输出格式进行更精细的控制,例如只转换指定工作表、指定单元格区域,或者自定义 JSON 的输出结构。针对这些需求,Spire.XLS 提供了相应的处理方式。

将指定工作表转换为 JSON

如果只需要转换工作簿中的某一个工作表,可以先将目标工作表复制到一个新的工作簿中,再将新工作簿保存为 JSON。

实现步骤

  1. 使用 LoadFromFile() 加载源工作簿。
  2. 通过索引或名称获取目标工作表。
  3. 创建一个新 Workbook 对象。
  4. 调用 Worksheets.AddCopy(),将目标工作表复制到新工作簿。
  5. 在新工作簿上调用 SaveToFile(),并指定输出格式为 FileFormat.Json。

完整代码示例

using System;
using Spire.Xls;

namespace ConvertWorksheetToJSON
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputFile = @"Sample.xlsx";
            string outputFile = @"sheet_output.json";

            try
            {
                using (Workbook sourceWorkbook = new Workbook())
                {
                    sourceWorkbook.LoadFromFile(inputFile);

                    // 通过索引获取第一个工作表
                    // 也可以按名称获取:sourceWorkbook.Worksheets["sheetName"]
                    Worksheet targetSheet = sourceWorkbook.Worksheets[0];

                    using (Workbook newWorkbook = new Workbook())
                    {
                        // 删除新工作簿中默认创建的工作表
                        newWorkbook.Worksheets.Clear();

                        // 将目标工作表复制到新工作簿
                        newWorkbook.Worksheets.AddCopy(targetSheet);

                        // 将新工作簿保存为 JSON 文件
                        newWorkbook.SaveToFile(outputFile, FileFormat.Json);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"转换过程中发生错误:{ex.Message}");
            }
        }
    }
}

将指定单元格区域转换为 JSON

如果只需要导出工作表中的部分数据,例如某个表格或指定区域,可以先将目标区域复制到一个新的工作簿中,再将新工作簿保存为 JSON。

实现步骤

  1. 加载源工作簿。
  2. 获取包含目标数据的工作表。
  3. 定义需要导出的单元格区域,例如 worksheet.Range["A1:D3"]。
  4. 创建一个新的 Workbook 对象。
  5. 使用 Worksheet.Copy() 将目标区域复制到新工作簿的工作表中。
  6. 调用 SaveToFile(),并指定 FileFormat.Json,将新工作簿保存为 .json 文件。

完整代码示例

using System;
using Spire.Xls;

namespace ConvertExcelToJSON
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputFile = @"Sample.xlsx";
            string outputFile = @"range_output.json";

            try
            {
                using (Workbook sourceWorkbook = new Workbook())
                {
                    sourceWorkbook.LoadFromFile(inputFile);
                    Worksheet sourceWorksheet = sourceWorkbook.Worksheets[0];

                    // 定义需要导出的区域,例如 A1:D3
                    CellRange sourceRange = sourceWorksheet.Range["A1:D3"];

                    using (Workbook targetWorkbook = new Workbook())
                    {
                        // 删除默认工作表
                        targetWorkbook.Worksheets.Clear();

                        // 新建一个用于保存所选区域的工作表
                        Worksheet targetWorksheet = targetWorkbook.Worksheets.Add("RangeData");

                        // 定义与源区域大小一致的目标区域
                        CellRange destinationRange = targetWorksheet.Range["A1:D3"];

                        // 将单元格的值和样式复制到新工作簿
                        sourceWorksheet.Copy(sourceRange, destinationRange, true);

                        // 将新工作簿保存为 JSON
                        targetWorkbook.SaveToFile(outputFile, FileFormat.Json);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"导出单元格区域时发生错误:{ex.Message}");
            }
        }
    }
}

自定义 JSON 输出格式

SaveToFile() 方法可以快速完成转换,但生成的 JSON 格式是固定的。如果需要更灵活地控制输出样式,可以使用 ExportDataTable() 方法将工作表数据导出为 DataTable,再使用 Newtonsoft.Json 进行序列化。通过这种方式,可以自定义属性名称、空值处理、日期格式和缩进方式等内容。

实现步骤

  1. 加载 Excel 文件。
  2. 获取目标工作表,并使用 ExportDataTable() 将数据导出为 DataTable。
  3. 配置 JsonSerializerSettings,定义 camelCase 命名、空值处理、日期格式等规则。
  4. 使用 JsonConvert.SerializeObject(),将 DataTable 按指定规则序列化为 JSON。
  5. 将生成的 JSON 字符串保存到文件。

完整代码示例

using System;
using System.Data;
using System.IO;
using Spire.Xls;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ConvertExcelToJSON
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = @"Sample.xlsx";
            string jsonOutputPath = "custom_output.json";

            try
            {
                using (Workbook workbook = new Workbook())
                {
                    workbook.LoadFromFile(excelFilePath);
                    Worksheet worksheet = workbook.Worksheets[0];

                    // 将表格数据转换为内存中的 DataTable
                    DataTable dataTable = worksheet.ExportDataTable(worksheet.AllocatedRange, true);

                    // 定义 JSON 序列化规则
                    JsonSerializerSettings settings = new JsonSerializerSettings
                    {
                        Formatting = Formatting.Indented, // 使用缩进,提高可读性
                        ContractResolver = new CamelCasePropertyNamesContractResolver(), // 使用 camelCase 命名
                        NullValueHandling = NullValueHandling.Ignore, // 忽略值为 null 的字段
                        DateFormatString = "yyyy-MM-dd" // 指定日期输出格式
                    };

                    // 根据规则将 DataTable 序列化为 JSON 字符串
                    string jsonResult = JsonConvert.SerializeObject(dataTable, settings);

                    // 将 JSON 字符串写入目标文件
                    File.WriteAllText(jsonOutputPath, jsonResult);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"自定义 JSON 序列化时发生错误:{ex.Message}");
            }
        }
    }
}

常用设置说明

设置 作用
Formatting = Formatting.Indented 添加换行和缩进,生成便于阅读的 JSON。
CamelCasePropertyNamesContractResolver 对适用的属性名称使用 camelCase,这是 JSON API 中常见的命名方式。
NullValueHandling = NullValueHandling.Ignore 忽略值为 null 或 DBNull.Value 的字段。
DateFormatString = "yyyy-MM-dd" 按指定格式输出 DateTime 或 DateTimeOffset 类型的值。

注:CamelCasePropertyNamesContractResolver 主要针对英文属性名进行首字母小写转换,若 Excel 列名为中文则保持原样。

此外,还可以通过自定义 JsonConverter、调整日期处理规则或使用其他 ContractResolver,进一步控制 JSON 输出结果。更多信息可参阅 Newtonsoft.Json 文档。

C# JSON 转 Excel 示例

将 JSON 转换为 Excel 时,可以先把 JSON 数据反序列化为 DataTable,再将该表格插入 Excel 工作表。

实现步骤

  1. 从文件、API 响应或字符串变量中读取 JSON 数据。
  2. 使用 Newtonsoft.Json.JsonConvert.DeserializeObject<DataTable>(),将 JSON 转换为 DataTable。
  3. 创建一个新的 Workbook 对象。
  4. 使用 InsertDataTable() 将 DataTable 写入新工作簿的工作表中。
  5. 设置表头和数据单元格的样式,提高可读性。
  6. 将工作簿保存为 Excel 文件。

完整代码示例

using System;
using System.Data;
using System.Drawing;
using Spire.Xls;
using Newtonsoft.Json;

namespace ConvertJSONToExcel
{
    class Program
    {
        static void Main(string[] args)
        {
            // 示例 JSON 数组
            string jsonInput = @"
            [
                {""姓名"":""张三"",""年龄"":30,""部门"":""销售部"",""入职日期"":""2020-05-12"",""全职"":true},
                {""姓名"":""李四"",""年龄"":25,""部门"":""市场部"",""入职日期"":""2021-09-01"",""全职"":false},
                {""姓名"":""王五"",""年龄"":40,""部门"":""技术部"",""入职日期"":""2018-03-15"",""全职"":true},
                {""姓名"":""赵六"",""年龄"":35,""部门"":""财务部"",""入职日期"":""2019-07-20"",""全职"":true}
            ]";

            string excelOutputPath = "output.xlsx";

            try
            {
                // 将 JSON 数组反序列化为 DataTable
                DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(jsonInput);

                using (Workbook workbook = new Workbook())
                {
                    Worksheet worksheet = workbook.Worksheets[0];

                    // 将 DataTable 插入工作表(包含列头)
                    worksheet.InsertDataTable(dataTable, true, 1, 1);

                    // 定义表头样式
                    CellStyle headerStyle = workbook.Styles.Add("HeaderStyle");
                    headerStyle.Font.IsBold = true;
                    headerStyle.Font.Size = 12;
                    headerStyle.Font.Color = Color.White;
                    headerStyle.Color = Color.DarkBlue;
                    headerStyle.HorizontalAlignment = HorizontalAlignType.Center;
                    headerStyle.VerticalAlignment = VerticalAlignType.Center;

                    // 将样式应用到表头行
                    int colCount = dataTable.Columns.Count;
                    worksheet.Range[1, 1, 1, colCount].CellStyleName = "HeaderStyle";

                    // 定义数据行样式
                    CellStyle dataStyle = workbook.Styles.Add("DataStyle");
                    dataStyle.HorizontalAlignment = HorizontalAlignType.Center;
                    dataStyle.VerticalAlignment = VerticalAlignType.Center;
                    dataStyle.Borders[BordersLineType.EdgeLeft].LineStyle = LineStyleType.Thin;
                    dataStyle.Borders[BordersLineType.EdgeRight].LineStyle = LineStyleType.Thin;
                    dataStyle.Borders[BordersLineType.EdgeTop].LineStyle = LineStyleType.Thin;
                    dataStyle.Borders[BordersLineType.EdgeBottom].LineStyle = LineStyleType.Thin;

                    // 将样式应用到数据行
                    int rowCount = dataTable.Rows.Count;
                    worksheet.Range[2, 1, rowCount + 1, colCount].CellStyleName = "DataStyle";

                    // 自动调整列宽
                    worksheet.AllocatedRange.AutoFitColumns();

                    // 将工作簿保存为 XLSX 文件
                    workbook.SaveToFile(excelOutputPath, ExcelVersion.Version2016);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"转换过程中发生异常:{ex.Message}");
            }
        }
    }
}

C# JSON 转 Excel 输出结果

处理带根节点或嵌套结构的 JSON

直接反序列化为 DataTable 的方式更适合结构扁平的 JSON 数组。如果记录被包含在根对象中,或者数据中包含嵌套对象和数组,则需要先提取目标记录并将嵌套结构扁平化,再转换为 DataTable。

例如,下面的 JSON 字符串同时包含根对象和嵌套数据:

string jsonInput = @"
{
  ""状态"": ""成功"",
  ""数据"": [
    {
      ""订单编号"": ""DD20260001"",
      ""客户"": {
        ""编号"": 1001,
        ""姓名"": ""王芳"",
        ""会员等级"": ""黄金""
      },
      ""商品"": [
        {
          ""名称"": ""无线蓝牙耳机"",
          ""数量"": 2,
          ""单价"": 299.00
        },
        {
          ""名称"": ""手机保护壳"",
          ""数量"": 1,
          ""单价"": 39.90
        }
      ],
      ""下单时间"": ""2026-07-10"",
      ""已付款"": true
    },
    {
      ""订单编号"": ""DD20260002"",
      ""客户"": {
        ""编号"": 1002,
        ""姓名"": ""陈明"",
        ""会员等级"": ""普通""
      },
      ""商品"": [
        {
          ""名称"": ""机械键盘"",
          ""数量"": 1,
          ""单价"": 459.00
        }
      ],
      ""下单时间"": ""2026-07-12"",
      ""已付款"": false
    }
  ]
}";

可以通过以下方法提取 数据 数组,将嵌套字段转换为适合表格展示的扁平字段,并返回 DataTable:

using System;
using System.Data;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

private static DataTable ConvertNestedJsonToDataTable(string jsonInput)
{
    // JSON 根节点既可以是对象,也可以是数组
    JToken rootToken = JToken.Parse(jsonInput);

    // 支持根节点直接为数组,或数组位于根对象的 "数据" 属性中
    JArray records = rootToken as JArray
        ?? ((rootToken as JObject)?["数据"] as JArray)
        ?? throw new ArgumentException("JSON 中未找到有效的记录数组。", nameof(jsonInput));

    // 将嵌套对象和数组转换为适合表格展示的字段
    var flattenedRecords = records.Select(record => new
    {
        订单编号 = (string)record["订单编号"] ?? string.Empty,

        // 将 客户 对象拆分为独立列
        客户编号 = (int?)record["客户"]?["编号"],
        客户姓名 = (string)record["客户"]?["姓名"] ?? string.Empty,
        会员等级 = (string)record["客户"]?["会员等级"] ?? string.Empty,

        // 商品 是"数组套对象",先把每个商品格式化成 "名称×数量" 的字符串,
        // 再用分号拼接成一列,同时把小计金额累加成 商品总额 列
        商品明细 = string.Join(
            "; ",
            (record["商品"] as JArray)?.Select(item =>
                $"{(string)item["名称"]}×{(int?)item["数量"]}")
            ?? Enumerable.Empty<string>()),

        商品总额 = (record["商品"] as JArray)?
            .Sum(item => ((decimal?)item["数量"] ?? 0) * ((decimal?)item["单价"] ?? 0)) ?? 0,

        下单时间 = (string)record["下单时间"] ?? string.Empty,
        已付款 = (bool?)record["已付款"] ?? false
    });

    // 将扁平化后的记录转换为 DataTable
    string flattenedJson =
        JsonConvert.SerializeObject(flattenedRecords);
    DataTable dataTable =
        JsonConvert.DeserializeObject<DataTable>(flattenedJson);

    if (dataTable == null || dataTable.Columns.Count == 0)
        throw new ArgumentException("JSON 中不包含可转换为表格的记录。", nameof(jsonInput));

    return dataTable;
}

上述字段映射是根据示例 JSON 的结构编写的。处理其他 JSON 结构时,需要根据实际的数据层级调整所选属性和输出列。

实用技巧

在 Excel 与 JSON 之间转换数据时,建议注意以下事项,以提高转换结果的准确性和可用性:

  • 检查源数据结构:转换前确认 Excel 中包含有效的列标题和数据区域,或确认 JSON 中存在可转换的记录数组,避免因数据结构不完整而导致转换失败。
  • 统一列名和字段命名:Excel 的列标题通常会成为 JSON 的字段名称。建议使用清晰、唯一且一致的列名,避免出现空标题、重复标题或不必要的空格。
  • 明确空值处理规则:根据实际需求,决定将空单元格转换为 null、空字符串、默认值,还是省略对应字段,并在整个转换过程中保持处理规则一致。
  • 正确保留数据类型:注意日期、数字、布尔值和文本等数据类型。对于员工编号、订单号等可能包含前导零的数据,应按文本处理,避免 00125 被转换为 125。
  • 先处理嵌套 JSON:如果 JSON 中包含嵌套对象或数组,应先将所需数据展开为普通字段,再写入 Excel。对于结构较复杂的数据,也可以分别写入不同的工作表。
  • 验证转换结果:转换完成后,应检查生成的 JSON 是否符合预期结构,并确认 Excel 中的列标题、行数、数据类型、空值和日期等内容是否准确保留。

常见问题解答

使用这些示例是否需要安装 Microsoft Excel?

不需要。Spire.XLS 是一个独立的 .NET 类库,可以读取、写入和转换 Excel 文件,不依赖 Microsoft Office 或 Excel Interop。

是否可以将旧版 .xls(Excel 97–2003)文件和新版 .xlsx 文件都转换为 JSON?

可以。LoadFromFile() 会自动识别文件格式,因此同一套代码既可以处理 .xls,也可以处理 .xlsx 文件。

是否可以将嵌套 JSON 转换为 Excel?

可以,但 JsonConvert.DeserializeObject<DataTable>() 更适合处理扁平的 JSON 数组。对于嵌套 JSON,应先将数据整理为简单的对象列表,再调用 InsertDataTable() 写入 Excel。

这种方法是否适用于 ASP.NET Core 或其他跨平台 .NET 应用?

适用。Spire.XLS 支持 .NET Framework、.NET Core 以及 .NET 5–10,因此这些代码可以运行在控制台应用、ASP.NET Core 服务,以及 Linux、macOS 等跨平台环境中。

总结

本文介绍了如何使用 C# 将整个 Excel 工作簿、指定工作表和单元格区域转换为 JSON,以及如何将 JSON 数据导入 Excel。结合 Spire.XLS 与 Newtonsoft.Json 库,开发者既可以处理简单的格式转换,也可以应对自定义 JSON 格式和嵌套数据处理等进阶场景。

获取免费许可证

如需完整体验 Spire.XLS for .NET 的功能,可以申请有效期为 30 天的免费临时许可证。

Spire.PDF 11.8.0 现已正式发布。该版本优化了转换 PDF 到 PDFA 的耗时,同时修复了多个与 PDF 转换、文本提取以及表格内容显示相关的问题。更多详情如下。

优化:

调整:

问题修复:


获取 Spire.PDF 11.8.0 请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-NET.html

Spire.PDF for Java 11.8.0 现已正式发布。该版本修复了内存溢出、透明度丢失及无法生成输出文档等问题,进一步提升了 PDF 转换过程的稳定性和正确性。详细更新内容如下:

问题修复:


获取 Spire.PDF for Java 11.8.0 请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-JAVA.html

Spire.PDF for C++ 11.8.1 已发布。本次更新修复了特定场景下,多产品同时使用的兼容性问题。详情请阅读以下内容。

问题修复:


获取 Spire.PDF for C++ 11.8.1 请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-CPP.html