我正在尝试将原始操作系统文件名持久存储,因此我需要获取OsStr
的原始字节。
似乎可以在* nix平台上调用as_bytes()
,但这不是在MS Windows上定义的。
有没有可移植的方法将OsStr
转换为字节?
OsStr
的观点是它的表现形式是特定于操作系统的。由于技术原因(@Shepmaster's answer提供了更多细节),实现有点复杂,但您可以这样想:
OsStr
归结为&[u8]
,因为POSIX函数接受并返回字节字符串;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>) }
。
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.
在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的W
或A
变体,尽管W
变体是强烈首选。
这变得更加困难,因为库也可能使用来自OS的不同编码。如果您在Windows上使用在* nix上创建的C库,则尤其如此 - 它几乎可以保证接受伪UTF-8字符串,然后进行某种有损转换以调用正确的底层API。
Rust通过提供不透明类型OsStr
和OsString
来避免所有这些。
如果你需要将OsStr
传递给接受UTF-8数据的函数,你需要将它转换为String
或&str
,然后你就可以得到它的字节。如果需要将其传递给接受LPCWSTR
的函数,首先需要转换为Vec<u16>
,然后将指向该缓冲区的指针传递给Windows API。你可以看到an example of how Rust itself does this。