Windows 10有一个有趣的特性,它将在锁定屏幕上显示“有趣的事实”和图像。有时候,这些图片是我想要用作背景的东西。
这些图像存储在%LocalAppData%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets中。
由于我不确定_cw5n1h2txyewy在Microsoft.Windows.ContentDeliveryManager文件夹中是否是常量,所以我只想搜索%LocalAppData%\Packages目录中的Microsoft.Windows.ContentDeliveryManager*,并提取第一个匹配该模式的目录。
然后,在该目录中,我希望复制图像并从每个图像中读取一个“魔术号”,该数字可以不同,但可以确定图像类型。在本例中,我使用前4个字节作为0x89 0x50 0x4E 0x47 (或0x89,然后是PNG),或使用6到9字节作为0x4A 0x46 0x49 0x46 (JFIF)或0x45 0x78 0x69 0x66 (Exif)。第一个条件将添加png扩展,第二个条件将添加jpg。
第一个函数是my detect_file_type,它评估文件内容并确定它是什么图像类型:
fn detect_file_type(data : &Vec<u8>) -> Option<String> {
if data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 { // ?PNG
Some("png".to_string())
} else if data[6] == 0x4A && data[7] == 0x46 && data[8] == 0x49 && data[9] == 0x46 { // JFIF
Some("jpg".to_string())
} else if data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66 { // Exif
Some("jpg".to_string())
} else {
None
}
}这是相当简单的。
接下来,我想要我的目录搜索功能:
fn find_dir(search : &str, path : PathBuf) -> Option<PathBuf> {
for entry in fs::read_dir(path).unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
if path.file_name().unwrap().to_str().unwrap().starts_with(search) {
return Some(path);
}
}
}
return None;
}再说一遍,很简单。我们坚持使用这两种方法的Option,以便能够处理错误案例(如果需要的话)。
最后,我们有了所有的关键工作:
fn main() {
let args =
App::new("Pull Windows Lock-Screen Pictures")
.version("0.1")
.about("Loads the images used for the main Windows 10 Lock-Screen backgrounds to the specified folder (or './out' if not specified).")
.arg(Arg::with_name("destination")
.help("The destination directory ('./out' by default)")
.takes_value(true)
.required(false))
.get_matches();
let my_dirs = Directories::with_prefix("windows_lock_screen_pictures", "Windows_Lock_Screen_Pictures").unwrap();
let home = my_dirs.bin_home().parent().unwrap().parent().unwrap().join("Packages");
let dir = find_dir("Microsoft.Windows.ContentDeliveryManager", home).unwrap().join("LocalState").join("Assets");
for entry in fs::read_dir(dir).unwrap() {
let path = entry.unwrap().path();
if !path.is_dir() {
let data = fs::read(&path).unwrap();
let path_str = path.display().to_string();
let file = path.file_name().unwrap().to_str().unwrap().to_string();
let path_ext =
match detect_file_type(&data) {
Some(path_ext) => {
let mut res = ".".to_string();
res.push_str(&path_ext);
res
},
_ => "".to_string()
};
let mut base_dest_dir = "".to_string();
let mut default = std::env::current_dir().unwrap().to_str().unwrap().to_string();
default.push_str("\\out\\");
let dest_dir = args.value_of("destination").unwrap_or(&default);
base_dest_dir.push_str(dest_dir);
if !Path::new(&base_dest_dir).exists() {
fs::create_dir(Path::new(&base_dest_dir)).expect("Could not create directory");
}
base_dest_dir.push_str(&file);
base_dest_dir.push_str(&path_ext);
println!("{} -> {}", path_str, base_dest_dir);
fs::write(Path::new(&base_dest_dir), data).expect("Could not write file");
}
}
}总的来说,我们保持的东西相当小,但仍然允许灵活性(以及我们所需要的大部分安全)。
我们的整个计划如下:
外箱拍击;
use std::fs::{self};
use std::path::{Path,PathBuf};
use clap::{App,Arg};
use dirs::{Directories};
fn detect_file_type(data : &Vec<u8>) -> Option<String> {
if data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 { // ?PNG
Some("png".to_string())
} else if data[6] == 0x4A && data[7] == 0x46 && data[8] == 0x49 && data[9] == 0x46 { // JFIF
Some("jpg".to_string())
} else if data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66 { // Exif
Some("jpg".to_string())
} else {
None
}
}
fn find_dir(search : &str, path : PathBuf) -> Option<PathBuf> {
for entry in fs::read_dir(path).unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
if path.file_name().unwrap().to_str().unwrap().starts_with(search) {
return Some(path);
}
}
}
return None;
}
fn main() {
let args =
App::new("Pull Windows Lock-Screen Pictures")
.version("0.1")
.about("Loads the images used for the main Windows 10 Lock-Screen backgrounds to the specified folder (or './out' if not specified).")
.arg(Arg::with_name("destination")
.help("The destination directory ('./out' by default)")
.takes_value(true)
.required(false))
.get_matches();
let my_dirs = Directories::with_prefix("windows_lock_screen_pictures", "Windows_Lock_Screen_Pictures").unwrap();
let home = my_dirs.bin_home().parent().unwrap().parent().unwrap().join("Packages");
let dir = find_dir("Microsoft.Windows.ContentDeliveryManager", home).unwrap().join("LocalState").join("Assets");
for entry in fs::read_dir(dir).unwrap() {
let path = entry.unwrap().path();
if !path.is_dir() {
let data = fs::read(&path).unwrap();
let path_str = path.display().to_string();
let file = path.file_name().unwrap().to_str().unwrap().to_string();
let path_ext =
match detect_file_type(&data) {
Some(path_ext) => {
let mut res = ".".to_string();
res.push_str(&path_ext);
res
},
_ => "".to_string()
};
let mut base_dest_dir = "".to_string();
let mut default = std::env::current_dir().unwrap().to_str().unwrap().to_string();
default.push_str("\\out\\");
let dest_dir = args.value_of("destination").unwrap_or(&default);
base_dest_dir.push_str(dest_dir);
if !Path::new(&base_dest_dir).exists() {
fs::create_dir(Path::new(&base_dest_dir)).expect("Could not create directory");
}
base_dest_dir.push_str(&file);
base_dest_dir.push_str(&path_ext);
println!("{} -> {}", path_str, base_dest_dir);
fs::write(Path::new(&base_dest_dir), data).expect("Could not write file");
}
}
}发布于 2019-04-20 01:11:11
几个普通的笔记。
”jpg”和”png”字符串。unwrap(),除非你确信它不应该失败。它实际上是不友好的用户,应该保留开发人员的错误。由于文件权限,大多数unwraps可能会失败。在这样一个小应用程序中,我可能会使用期望来提供更友好的错误信息。在更大的部分中,链接文档包含了在结果类型上所期望的所有方法。有些事我喜欢:
return关键字。混淆:
我们已经审查对方的密码很长时间了。我一直对你倾向于使用密集逻辑而不是提取方法感到惊讶。我不介意这种密集的逻辑,我只是认为您有一个通用的机会来命名事物并提高抽象级别。对于这个应用程序,我希望代码读起来像这样,隐藏较低层次的细节。
let outdir = parse_args().or_else(“./out”);
let files = get_files();
copy_files(files, outdir);https://codereview.stackexchange.com/questions/217745
复制相似问题