如何将OsStr转换为&[u8] / Vec 在Windows上?

问题描述 投票:8回答:2

我正在尝试将原始操作系统文件名持久存储,因此我需要获取OsStr的原始字节。

似乎可以在* nix平台上调用as_bytes(),但这不是在MS Windows上定义的。

有没有可移植的方法将OsStr转换为字节?

string rust
2个回答
2
投票

OsStr的观点是它的表现形式是特定于操作系统的。由于技术原因(@Shepmaster's answer提供了更多细节),实现有点复杂,但您可以这样想:

  • 在POSIX系统上,OsStr归结为&[u8],因为POSIX函数接受并返回字节字符串;
  • 在Windows上,OsStr可以被认为是&[u16],因为Win32 Unicode函数接受并返回16位单元数组的字符串。

由于本机Windows API接受16位“宽字符”1的序列,这就是OsStr旨在存储的内容。虽然OsStr可以转换为字节,因为任何东西都可以转换为字节,但这种表示没有用,因为这些字节对用户和系统都没有意义。这就是为什么OsStr不提供在Windows上以字节形式检索内容的方法。但是,它确实提供了OsStr::encode_wide(),它迭代了在Win32中有用的底层u16值。在另一个方向,OsString::from_wide()可用于从一片OsString值创建u16

您可以决定持久层如何处理平台之间的这种差异。 Rust的OsStr提供的是实现往返的必要工具,但代码之间的代码必然不同。例如,serde将effectively treating的差异解析为enum OsString { Unix(Vec<u8>), Windows(Vec<u16>) }


1 Windows wide character strings are sometimes described as UTF-16 because that is how they are interpreted at a higher level, but this is not correct for all OS strings. A Windows file name can contain pairs of u16 values that are not valid UTF-16, and still be usable. This is why it's not possible to represent Windows strings as bytes by e.g. converting them to UTF-8.

4
投票

在Rust 1.16中,没有用于在Windows上获取OsStr的字节的已定义接口。 OsStr delegates to system-specific code的实际实施。在* nix,这是一个wrapper around a Vec<u8>;在Windows上,这是一个wrapper around a Wtf8Buf。虽然Wtf8Buf是用Vec<u8>实现的,但实现细节并未公开。有关WTF-8的更多细节可用on its website,其中包括此引用,强调我的:

在Windows上(在其API中使用可能格式错误的UTF-16),Rust标准库在内部使用WTF-8作为OS字符串,但不公开WTF-8字节序列。

“问题”是在不同的平台上,在将其传递给操作系统接口时,没有统一的“字符串”概念。在* nix上,通常接口接受类似UTF-8的东西,除了它们不处理嵌入的NUL值。在Windows上,它取决于您是否调用API的WA变体,尽管W变体是强烈首选。

这变得更加困难,因为库也可能使用来自OS的不同编码。如果您在Windows上使用在* nix上创建的C库,则尤其如此 - 它几乎可以保证接受伪UTF-8字符串,然后进行某种有损转换以调用正确的底层API。

Rust通过提供不透明类型OsStrOsString来避免所有这些。


如果你需要将OsStr传递给接受UTF-8数据的函数,你需要将它转换为String&str,然后你就可以得到它的字节。如果需要将其传递给接受LPCWSTR的函数,首先需要转换为Vec<u16>,然后将指向该缓冲区的指针传递给Windows API。你可以看到an example of how Rust itself does this

© www.soinside.com 2019 - 2024. All rights reserved.