Skip to main content

使用 Jint 的 .NET 中的工作表

Jint[^1] 是 .NET Standard 和 .NET Core 的 JavaScript 解释器。它内置了对 .NET byte[] 和 ES6 Uint8Array 二进制数据的支持。

¥Jint[^1] is a JavaScript interpreter for .NET Standard and .NET Core. It has built-in support for binary data with .NET byte[] and ES6 Uint8Array.

SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。

¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.

该演示使用 Jint 和 SheetJS 来读取和写入电子表格。我们将探讨如何在 Jint 引擎中加载 SheetJS、与 C# 程序交换二进制数据以及处理电子表格和结构化数据。

¥This demo uses Jint and SheetJS to read and write spreadsheets. We'll explore how to load SheetJS in the Jint engine, exchange binary data with a C# program, and process spreadsheets and structured data.

"集成示例" 部分包括一个完整的命令行工具,用于读取任意工作簿并将数据写入 XLSB(Excel 2007+ 二进制格式)工作簿。

¥The "Integration Example" section includes a complete command-line tool for reading arbitrary workbooks and writing data to XLSB (Excel 2007+ Binary Format) workbooks.

遥测

dotnet 命令嵌入遥测技术。

¥The dotnet command embeds telemetry.

DOTNET_CLI_TELEMETRY_OPTOUT 环境变量应设置为 1

¥The DOTNET_CLI_TELEMETRY_OPTOUT environment variable should be set to 1.

"平台配置" 包含有关在支持的平台上设置环境变量的说明。

¥"Platform Configuration" includes instructions for setting the environment variable on supported platforms.

集成详情

¥Integration Details

大多数集成功能都没有记录。此说明基于版本 3.1.0

¥Most of the integration functions are not documented. This explanation is based on version 3.1.0.

SheetJS 独立脚本 可以在 Jint 引擎实例中进行解析和评估。

¥The SheetJS Standalone scripts can be parsed and evaluated in a Jint engine instance.

初始化 Jint

¥Initialize Jint

可以在一行中创建 Jint.Engine 对象:

¥A Jint.Engine object can be created in one line:

var engine = new Jint.Engine();

Jint 不公开 NodeJS global,但提供 globalThis。使用 Jint.Engine#Evaluate,可以创建 global 全局变量:

¥Jint does not expose the NodeJS global but does provide globalThis. Using Jint.Engine#Evaluate, a global global variable can be created:

JS 代码是

¥The JS code is

global = globalThis;
engine.Evaluate("global = globalThis");

加载 SheetJS 脚本

¥Load SheetJS Scripts

可以通过使用 System.IO.File.ReadAllText 从文件系统读取脚本并在 Jint 引擎实例中进行评估来加载主库:

¥The main library can be loaded by reading the scripts from the file system with System.IO.File.ReadAllText and evaluating in the Jint engine instance:

/* read and evaluate the shim script */
string src = System.IO.File.ReadAllText("shim.min.js");
engine.Evaluate(src);
/* read and evaluate the main library */
engine.Evaluate(System.IO.File.ReadAllText("xlsx.full.min.js"));

要确认库已加载,可以检查 XLSX.version

¥To confirm the library is loaded, XLSX.version can be inspected:

Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));

Jint Evaluate 方法返回通用 Jint.Native.JsValue 对象。

¥The Jint Evaluate method returns a generic Jint.Native.JsValue object.

当 JS 表达式返回字符串时,JsValue 对象是 Jint.Native.JsString 的实例。C# ToString 将返回基础 string 值。

¥When the JS expression returns a string, the JsValue object is an instance of Jint.Native.JsString. C# ToString will return the underlying string value.

读取文件

¥Reading Files

在 C# 中,System.IO.File.ReadAllBytes 将文件数据读取到 byte[] 字节数组中:

¥In C#, System.IO.File.ReadAllBytes reads file data into a byte[] byte array:

string filename = "pres.xlsx";
byte[] buf = File.ReadAllBytes(filename);

Jint 本身支持字节数组的 Uint8Array 构造:

¥Jint natively supports Uint8Array construction from the byte array:

Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(buf);

Jint.Engine#SetValue 会将 Uint8Array 分配给 JS 中的作用域变量:

¥Jint.Engine#SetValue will assign the Uint8Array to a scope variable in JS:

engine.SetValue("buf", u8);

可以使用 SheetJS read 方法 [^2] 从 JS 中解析 buf 变量:

¥The buf variable can be parsed from JS with the SheetJS read method[^2]:

JS 代码是

¥The JS code is

var wb = XLSX.read(buf);
engine.Evaluate("var wb = XLSX.read(buf);");

wb 是一个 SheetJS 工作簿对象。"SheetJS 数据模型" 部分描述了对象结构,"API 参考" 部分描述了各种辅助函数。

¥wb is a SheetJS workbook object. The "SheetJS Data Model" section describes the object structure and the "API Reference" section describes various helper functions.

写入文件

¥Writing Files

SheetJS write 方法 [^3] 可以编写工作簿。选项 type: "buffer" 指示库生成 Uint8Array 对象。

¥The SheetJS write method[^3] can write workbooks. The option type: "buffer" instructs the library to generate Uint8Array objects.

导出为 XLSB 格式的 JS 代码为:

¥The JS code for exporting to the XLSB format is:

var u8 = XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'});

可以使用 bookType 选项 [^4] 更改文件格式

¥The file format can be changed with the bookType option[^4]

Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})");

xlsb 代表 Uint8Arrayxlsb.AsUint8Array() 将字节作为 byte[] 数组返回,可以使用 System.IO.File.WriteAllBytes 导出:

¥xlsb represents a Uint8Array. xlsb.AsUint8Array() returns the bytes as a byte[] array which can be exported with System.IO.File.WriteAllBytes:

byte[] outfile = xlsb.AsUint8Array();
System.IO.File.WriteAllBytes("SheetJSJint.xlsb", outfile);

集成示例

¥Integration Example

测试部署

该演示在以下部署中进行了测试:

¥This demo was tested in the following deployments:

架构Jint日期
darwin-x643.0.12024-03-15
darwin-arm3.1.22024-05-25
win10-x643.1.02024-04-17
win11-arm3.1.22024-05-25
linux-x643.1.02024-04-25
linux-arm3.1.22024-05-25

平台配置

¥Platform Configuration

  1. DOTNET_CLI_TELEMETRY_OPTOUT 环境变量设置为 1

    ¥Set the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to 1.

How to disable telemetry (click to hide)

将以下行添加到 .profile.bashrc.zshrc

¥Add the following line to .profile, .bashrc and .zshrc:

(add to .profile , .bashrc , and .zshrc)
export DOTNET_CLI_TELEMETRY_OPTOUT=1

关闭并重新启动终端以加载更改。

¥Close and restart the Terminal to load the changes.

  1. 安装.NET

    ¥Install .NET

Installation Notes (click to show)

For macOS x64 and ARM64, install the dotnet-sdk Cask with Homebrew:

brew install --cask dotnet-sdk

For Steam Deck Holo and other Arch Linux x64 distributions, the dotnet-sdk and dotnet-runtime packages should be installed using pacman:

sudo pacman -Syu dotnet-sdk dotnet-runtime

https://dotnet.microsoft.com/en-us/download/dotnet/6.0 is the official source for Windows and ARM64 Linux versions.

  1. 在 macOS 中打开新的终端窗口或在 Windows 中打开 PowerShell 窗口。

    ¥Open a new Terminal window in macOS or PowerShell window in Windows.

基础项目

¥Base Project

  1. 使用 dotnet 工具创建一个新文件夹 SheetJSJint 和一个新项目:

    ¥Create a new folder SheetJSJint and a new project using the dotnet tool:

mkdir SheetJSJint
cd SheetJSJint
dotnet new console
dotnet run
  1. 使用 NuGet 工具添加 Jint:

    ¥Add Jint using the NuGet tool:

dotnet nuget add source https://www.myget.org/F/jint/api/v3/index.json
dotnet add package Jint --version 3.1.2

要验证 Jint 是否已安装,请将 Program.cs 替换为以下内容:

¥To verify Jint is installed, replace Program.cs with the following:

Program.cs
var engine = new Jint.Engine();
Console.WriteLine("Hello {0}", engine.Evaluate("'Sheet' + 'JS'"));

保存后运行程序:

¥After saving, run the program:

dotnet run

终端应显示 Hello SheetJS

¥The terminal should display Hello SheetJS

添加 SheetJS

¥Add SheetJS

  1. 下载 SheetJS Standalone 脚本、shim 脚本和测试文件。将所有三个文件移动到项目目录:

    ¥Download the SheetJS Standalone script, shim script and test file. Move all three files to the project directory:

curl -LO https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/shim.min.js
curl -LO https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -LO https://xlsx.nodejs.cn/pres.xlsx
  1. Program.cs 替换为以下内容:

    ¥Replace Program.cs with the following:

Program.cs
var engine = new Jint.Engine();
engine.Evaluate("global = globalThis;");
engine.Evaluate(File.ReadAllText("shim.min.js"));
engine.Evaluate(File.ReadAllText("xlsx.full.min.js"));
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));

保存后运行程序:

¥After saving, run the program:

dotnet run

The terminal should display SheetJS version 0.20.3

读写文件

¥Read and Write Files

  1. Program.cs 替换为以下内容:

    ¥Replace Program.cs with the following:

Program.cs
using Jint;

/* Initialize Jint */
var engine = new Jint.Engine();
engine.Evaluate("global = globalThis;");

/* Load SheetJS Scripts */
engine.Evaluate(File.ReadAllText("shim.min.js"));
engine.Evaluate(File.ReadAllText("xlsx.full.min.js"));
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));

/* Read and Parse File */
byte[] filedata = File.ReadAllBytes(args[0]);
Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(filedata);
engine.SetValue("buf", u8);
engine.Evaluate("var wb = XLSX.read(buf);");

/* Print CSV of first worksheet*/
engine.Evaluate("var ws = wb.Sheets[wb.SheetNames[0]];");
Jint.Native.JsValue csv = engine.Evaluate("XLSX.utils.sheet_to_csv(ws)");
Console.Write(csv);

/* Generate XLSB file and save to SheetJSJint.xlsb */
Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})");
File.WriteAllBytes("SheetJSJint.xlsb", xlsb.AsUint8Array());

保存后,运行程序并将测试文件名作为参数传递:

¥After saving, run the program and pass the test file name as an argument:

dotnet run pres.xlsx

如果成功,程序会将第一张表的内容打印为 CSV 行。它还将创建可以在 Excel 或其他电子表格编辑器中打开的 SheetJSJint.xlsb

¥If successful, the program will print the contents of the first sheet as CSV rows. It will also create SheetJSJint.xlsb which can be opened in Excel or another spreadsheet editor.

在不带文件名参数的情况下运行 dotnet run 将显示错误:

¥Running dotnet run without the filename argument will show an error:

Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Program.<Main>$(String[] args) in C:\Users\Me\SheetJSJint\Program.cs:line 13

该命令必须使用指定工作簿名称的参数运行:

¥The command must be run with an argument specifying the name of the workbook:

dotnet run pres.xlsx

如果省略 using Jint; 指令,构建将失败:

¥If the using Jint; directive is omitted, the build will fail:

'JsValue' does not contain a definition for 'AsUint8Array' and no accessible extension method 'AsUint8Array' accepting a first argument of type 'JsValue' could be found

独立应用

¥Standalone Application

  1. 查找你的平台 [^5] 的运行时标识符(RID)。下面列出了测试平台的 RID 值:

    ¥Find the runtime identifier (RID) for your platform[^5]. The RID values for tested platforms are listed below:

平台RID
英特尔 Macosx-x64
ARM64 苹果电脑osx-arm64
Windows 10 (x64)win10-x64
Windows 11(ARM)win-arm64
Linux (x64)linux-x64
Linux(ARM)linux-arm64
  1. 构建独立应用。

    ¥Build the standalone application.

Tested platforms (click to hide)

对于 Intel Mac,RID 为 osx-x64,命令为

¥For Intel Mac, the RID is osx-x64 and the command is

dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
  1. 将生成的可执行文件复制到项目目录。

    ¥Copy the generated executable to the project directory.

二进制文件名称将为 SheetJSJintSheetJSJint.exe,具体取决于操作系统。

¥The binary name will be SheetJSJint or SheetJSJint.exe depending on OS.

步骤 9 输出的最后一行将打印输出文件夹。

¥The last line of the output from Step 9 will print the output folder.

Tested platforms (click to hide)

对于 Intel Mac,RID 为 osx-x64,命令为:

¥For Intel Mac, the RID is osx-x64 and the command is:

cp bin/Release/net*/osx-x64/publish/SheetJSJint .
  1. 运行生成的命令。

    ¥Run the generated command.

./SheetJSJint pres.xlsx

[^1]: Jint 项目推荐 "MyGet" 服务。据开发者称,"NuGet" 包 是 "偶尔发表"。

¥The Jint project recommends the "MyGet" service. According to the developers, the "NuGet" package is "occasionally published".

[^2]: 见 read 于 "读取文件"

¥See read in "Reading Files"

[^3]: 见 write 于 "写入文件"

¥See write in "Writing Files"

[^4]: 有关 bookType 的详细信息,请参阅 "支持的输出格式" 于 "写入文件"

¥See "Supported Output Formats" in "Writing Files" for details on bookType

[^5]: 请参阅 .NET 文档中的 ".NET RID 目录"

¥See ".NET RID Catalog" in the .NET documentation