【问题标题】:Is there any way to include binary or text files in a Rust library?有没有办法在 Rust 库中包含二进制或文本文件?
【发布时间】:2015-12-21 07:44:50
【问题描述】:

我正在尝试创建一个库,并且我想在其中包含一些二进制(或文本)文件,这些文件将包含将在运行时解析的数据。

我的目的是控制这些文件,不断更新它们,并在每次更新时更改库的版本。

这可以通过货物实现吗?如果是这样,我如何从我的库中访问这些文件?

我想到的一种解决方法是包含一些带有结构和/或常量的.rs 文件,例如&str,它将存储数据,但我觉得它有点难看。

编辑:

我已将接受的答案更改为更适合我情况的答案,但请查看Shepmaster's answer,因为这可能更适合您的情况。

【问题讨论】:

  • 将在运行时解析 => 为什么?由于数据是静态的,将已经解析的数据存储在二进制文件中比在运行时解析它更有效。 Rust 在编译时可以表示的内容相当有限(很不幸),但是您提到维护一个 .rs 文件,因此在您的情况下似乎是可能的。如果是这种情况,那么我建议使用 build.rs 文件,这是 Rust 中的“构建脚本”,它允许您在构建“正确”之前解析源文件并生成 .rs 文件。
  • 更准确地说,这些数据已经被解析并且需要移动到结构体中,比如HashMap,它不能被初始化(至少不使用lazy_static crate)。这就是为什么我需要在运行时“解析”它们。当我想更新数据时,将它们放在二进制(或文本)文件中可以更容易地只替换这个文件。然而,结合使用build.rslazy_static crate 听起来像是一个更好的选择,我会试一试。感谢您的建议!

标签: rust libraries binaryfiles rust-cargo


【解决方案1】:

免责声明:我在评论中提到过,但让我在这里重申一下,因为它给了我更多阐述的空间。

正如 Shepmaster 所说,可以使用 include_bytes!include_str! 宏在 Rust 库/可执行文件中包含文本或二进制逐字记录。

但是,在你的情况下,我会避免它。通过将内容的解析推迟到运行时:

  • 您允许构建有缺陷的工件。
  • 您会产生(更多)运行时开销(解析时间)。
  • 您会产生(更多)空间开销(解析代码)。

Rust 承认了这个问题,并提供了多种代码生成机制来克服这些限制:

  • 宏:如果逻辑可以编码成宏,那么可以直接包含在源文件中
  • 插件:已启动的宏,可以对任意逻辑进行编码并生成精细代码(参见regex!
  • build.rs:在编译之前运行的独立“Rust 脚本”,其作用是生成 .rs 文件

在您的情况下,build.rs 脚​​本听起来很合适:

  • 通过将解析代码移到那里,您可以交付更轻量级的工件
  • 通过提前解析,您可以交付更快的工件
  • 通过提前解析,您可以交付正确的工件

你的解析结果可以用不同的方式编码,从函数到静态(可能是lazy_static!),因为build.rs可以生成任何有效的Rust代码。

您可以在the Cargo Documentation中看到如何使用build.rs;您将在那里找到如何将其与 Cargo 集成以及如何创建文件(等等)。

【讨论】:

    【解决方案2】:

    include_bytes! 宏似乎与您想要的很接近。它只给你一个字节数组的引用,所以你必须从那个开始做任何解析:

    static HOST_FILE: &'static [u8] = include_bytes!("/etc/hosts");
    
    fn main() {
        let host_str = std::str::from_utf8(HOST_FILE).unwrap();
    
        println!("Hosts are:\n{}", &host_str[..42]);
    }
    

    如果你有 UTF-8 内容,你可以使用include_str!,正如Benjamin Lindley所指出的那样:

    static HOST_FILE: &'static str = include_str!("/etc/hosts");
    
    fn main() {
        println!("Hosts are:\n{}", &HOST_FILE[..42]);
    }
    

    【讨论】:

    • 如果你想要文本(而不是二进制数据),并且它已经是utf8格式,你不能只使用include_str!,而不是使用include_bytes!然后转换它吗? -- let host_str = include_str!("/etc/hosts");
    • @BenjaminLindley 嗯,好点子!我看到include! 并意识到它不对但直接跳过include_str!
    猜你喜欢
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 2012-11-18
    • 2011-12-04
    • 2019-06-08
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多