这段代码遍历一个文件夹,并查找以.txt
结尾的文件。接下来,我想获取std::ffi::os_str::OsStr
类型的entry.file_name()
,并将其与BASE_URL
连接以形成URL。
const FOLDER_NAME: &str = "/tmp";
const PATTERN: &str = ".txt";
const BASE_URL: &str = "http://192.168.1.100:3310/";
use std::error::Error;
use std::ffi::OsStr;
use walkdir::WalkDir;
fn main() -> Result<(), Box<dyn Error>> {
println!("Walking folder {}", FOLDER_NAME);
let valid_entries = WalkDir::new(FOLDER_NAME)
.into_iter()
.flat_map(|e| e)
.flat_map(|e| {
let name = e.file_name().to_str()?;
if name.contains(PATTERN) {
Some(e)
} else {
None
}
});
print_type_of(&valid_entries);
for entry in valid_entries {
println!("This file matches: {:?}", entry);
let metadata = entry.metadata()?;
let size = metadata.len();
let name = entry.file_name();
let fullpath = entry.path().display();
println!("path: {}, filename: {:?}, Len: {:?}", fullpath, name, size);
print_type_of(&name);
//let url = format!("{}{}",BASE_URL, name); <--- this, how do I do this?
}
Ok(())
}
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
blowup的示例输出:
error[E0277]: `std::ffi::OsStr` doesn't implement `std::fmt::Display`
--> src/main.rs:34:38
|
34 | let url = format!("{}{}",BASE_URL, name);
| ^^^^ `std::ffi::OsStr` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `std::ffi::OsStr`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required because of the requirements on the impl of `std::fmt::Display` for `&std::ffi::OsStr`
= note: required by `std::fmt::Display::fmt`
在Go中,我这样做:
video_url := baseURL + *video.Name
req, err := http.NewRequest("HEAD", video_url, nil)
if err != nil {
log.Println("Err", err)
}
在Rust中正确的方法是什么?
我得到的最接近的是:
let url = format!("{}{:?}", BASE_URL, name);
println!("url {}", url);
其给出:
This file matches: DirEntry("/tmp/a.txt")
path: /tmp/a.txt, filename: "a.txt", Len: 820805
&std::ffi::os_str::OsStr
&str
url http://192.168.1.100:3310/"a.txt" <- malformed
This file matches: DirEntry("/tmp/somefile.txt")
path: /tmp/somefile.txt, filename: "somefile.txt", Len: 13
&std::ffi::os_str::OsStr
&str
url http://192.168.1.100:3310/"somefile.txt" <- malformed
有了这个,我必须弄清楚如何删除"
s。当然感觉有一个更好的方式,我不知道..
既然正确的方法使用了match
表达式,那么我如何用它来构建URL呢?
let name = entry.file_name();
let name_to_str = entry.file_name().to_str();
let url = match name_to_str {
Some(name) => format!("{}{:?}",BASE_URL, name_to_str).replace("\"", ""),
_ => None
};
2条答案
按热度按时间hvvq6cgz1#
您可以使用
OsStr
中的to_str
方法来获取Option<&str>
。它返回Option
,因为如果字符串不包含有效的Unicode,转换可能会失败。如果你绝对确定它将永远是有效的Unicode,你可以只unwrap
Option
。因此,您可以按如下方式创建您的URL:编辑1
{:?}
用于调试打印。它使用Debug
trait。如链接所示,Debug应该在面向程序员的调试上下文中格式化输出
在你的例子中,这恰好是你想要的字符串,但这不是它的预期行为。我仍然推荐使用为您的用例显式提供的方法
to_str
yeotifhr2#
我怀疑URL原始数据的正确类型不是真正的
str
。完全编码的URL,使用percent-encoding编码特殊字符,是纯ASCII。当你解码它时,你会得到URL的许多部分(协议,域名,
'/'
,'?'
,'&'
等之间的各个部分)作为未解释的二进制数据(即[u8]
),不像str
/String
强制的那样有效的UTF-8。为了更健壮,您可能希望直接从原始数据中对url的各个部分进行百分比编码。特别是,文件名应该直接从
&OsStr
/OsString
进行URL编码。这样你就不会冒着让非UTF-8文件名破坏你的代码的风险,甚至更糟的是,文件名中有潜在的危险字符,如?
,=
和&
,成为攻击向量。实际上,使用crate urlencoding,它会是这样的:
这将完全按照您的操作系统中的表示对文件名进行编码。也就是说,如果您的操作系统支持
as_bytes()
。不幸的是,并非所有操作系统都是如此。这是可以理解的:我不知道如何将Windows 16位
wchar
编码为大于255的URL。在这种情况下,惯例似乎是在URL编码之前将整个字符串转换为UTF-8(使用.to_str()
,如另一个答案所建议的),但然后文件名可能是无效的UTF-16,在这种情况下转换将失败,我猜在URL中表示这样的文件名确实是不可能的,并且你应该在你的程序中返回一个错误(见问号操作符)。