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

时间:2017-03-29 03:03:11

标签: string rust

我正在尝试将原始操作系统文件名保存到存储中,因此我需要获取rdd.map的原始字节。

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

是否有可移植的方式将OsStr转换为字节?

2 个答案:

答案 0 :(得分:3)

在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作为操作系统字符串,但确实如此   不暴露WTF-8字节序列

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

这变得更加困难,因为库也可能使用来自操作系统的不同编码。如果你使用在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

答案 1 :(得分:2)

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

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

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

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

<小时/> 1 Windows宽字符字符串有时被描述为UTF-16,因为它是在更高级别解释它们的方式,但这对于所有 OS字符串不正确。 Windows文件名可以包含有效UTF-16的full_day个值对,并且仍然可用。这就是为什么不可能通过例如将Windows字符串表示为字节的原因。将它们转换为UTF-8。