如何在写入JSON文件时转义PathBuf变量中的反斜杠字符?
我对Rust很陌生,这段代码是一个人工学习项目的一部分。记住这一点;) 我有一组元组:如何在写入JSON文件时转义PathBuf变量中的反斜杠字符?,json,rust,Json,Rust,我对Rust很陌生,这段代码是一个人工学习项目的一部分。记住这一点;) 我有一组元组:&[(i32,String,String,PathBuf)],它们被传递到一个函数中,该函数用于将数据写入JSON文件 问题:当我将PathBuf转换为&str时-写入文件的路径具有未转换的反斜杠字符,因此JSON无效 代码如下: use std::io; use std::io::prelude::*; use std::fs::File; use std::path::PathBuf; pub fn wr
&[(i32,String,String,PathBuf)]
,它们被传递到一个函数中,该函数用于将数据写入JSON文件
问题:当我将PathBuf
转换为&str
时-写入文件的路径具有未转换的反斜杠字符,因此JSON无效
代码如下:
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::PathBuf;
pub fn write_review_queue(ordered_review_queue: &[(i32, String, String, PathBuf)]) -> io::Result<()> {
let output_file = "C:\\Dev\\Temp\\ReviewQueue\\review_queue.json";
let mut buffer = try!(File::create(output_file));
try!(buffer.write("{".to_string().as_bytes()));
let mut is_first_item = true;
for review_item in ordered_review_queue {
if !is_first_item {
try!(buffer.write(",".to_string().as_bytes()));
}
is_first_item = false;
let json_string = "\"ReviewItem\": ".to_string() +
"{\"Index\": " + &review_item.0.to_string() +
", \"ReviewItemName\": \"" + &review_item.1 +
"\", \"ReviewItemPath\": \"" + &review_item.2 +
"\", \"MetadataPath\": \"" + review_item.3.to_str().unwrap() +
"\"}";
try!(buffer.write(json_string.as_bytes()));
}
try!(buffer.write("}".to_string().as_bytes()));
Ok(())
}
为MetadataPath
s生成PathBuf
s的代码如下:
let metadata_files = metadata_read::read_filenames_from_dir("C:\\Dev\\Temp\\ReviewQueue\\Metadata");
if !metadata_files.is_ok() {
println!("reading metadata filenames failed");
return;
}
let mut metadata_counts = Vec::new();
for file in metadata_files.unwrap() {
let metadata_field_count = metadata_read::count_nonempty_metadata_fields(&file, &keys);
metadata_counts.push(metadata_field_count.unwrap());
}
以及count\u nonempty\u metadata\u字段
功能:
pub fn count_nonempty_metadata_fields(file_path: &PathBuf, metadata_keys: &[String]) -> Result<(i32, String, String, PathBuf), io::Error>
{
// a bunch of code here...
let path = file_path.to_path_buf();
Ok((key_count, review_item_name, review_item_path, path))
}
它确实会改变输出,例如
{
"ReviewItem": {
"Index": 1,
"ReviewItemName": "Crying Cat",
"ReviewItemPath": "C:/Temp",
"MetadataPath": "C:/Dev/Temp/ReviewQueue/Metadata\cryingcat.json"
},
"ReviewItem": {
"Index": 2,
"ReviewItemName": "Rusty Rat",
"ReviewItemPath": "C:/Temp",
"MetadataPath": "C:/Dev/Temp/ReviewQueue/Metadata\rustyrat.json"
}
}
但这仍然不对
问题
字符串
,那么如何将PathBuf
s的路径内容转换为带有正斜杠或转义反斜杠的格式?我在API中遗漏了什么吗Json
对象来构建数据(这可能更可靠)?如果是这样,将Json
对象的内容写入文件的正常方式是什么foo.1
就是这个名字吗。。。还是说它是foo.2
一旦完成,您可以简单地输出切片:
extern crate rustc_serialize;
use rustc_serialize::json;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::PathBuf;
#[derive(RustcEncodable)]
struct Item {
index: i32,
name: String,
path: String,
metadata_path: PathBuf,
}
fn write_review_queue(ordered_review_queue: &[Item]) -> io::Result<()> {
let mut buffer = try!(File::create("/tmp/output"));
write!(buffer, "{}", json::as_json(&ordered_review_queue))
}
fn main() {
let a = [Item { index: 0, name: "He\"llo".into(), path: "Good\\bye".into(), metadata_path: PathBuf::from(r#"C:\path\with'n\special"\chars"#)}];
write_review_queue(&a).expect("Failed");
}
重要的是要知道PathBuf
s是而不是字符串。具体来说,它们是依赖于平台的抽象。在类Unix系统上,路径是接近UTF-8但不是UTF-8的字节集合,在Windows上,路径接近但不是UCS-2
您必须决定什么样的有损转换适合将其转换为真正的UTF-8。我将使用标准库中内置的。我还为类型实现了ToJson
,以允许更多定制:
extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::PathBuf;
use std::collections::BTreeMap;
struct Item {
index: i32,
name: String,
path: String,
metadata_path: PathBuf,
}
impl ToJson for Item {
fn to_json(&self) -> Json {
let mut obj = BTreeMap::new();
obj.insert("Index".to_string(), self.index.to_json());
obj.insert("ReviewItemName".to_string(), self.name.to_json());
obj.insert("ReviewItemPath".to_string(), self.path.to_json());
obj.insert("MetadataPath".to_string(), self.metadata_path.to_string_lossy().to_json());
obj.to_json()
}
}
fn write_review_queue(ordered_review_queue: &[Item]) -> io::Result<()> {
let mut buffer = try!(File::create("/tmp/output"));
write!(buffer, "{}", json::as_json(&ordered_review_queue.to_json()))
}
fn main() {
let a = [Item { index: 0, name: "He\"llo".into(), path: "Good\\bye".into(), metadata_path: PathBuf::from(r#"C:\path\with'n\special"\chars"#)}];
write_review_queue(&a).expect("Failed");
}
感谢这个答案的深度,除了
PathBuf
/to_string\u lossy()
信息之外,还有许多其他改进需要解决。您所说的“另外,您的输出有一个具有相同两个键的对象。虽然不是无效的,但它可能不是您想要的。”?您指的是重复出现的ReviewItem
?也不太适用于JSON
,但是,如果我正确解释了您的意思,我可以输出一个“有序的值列表”(数组),而不是“名称/值对集合”(术语来源)?在这种情况下,我不需要ReviewItem
。。。谢谢@GavinHope双重出现ReviewItem
-是,第二次出现的键将覆盖第一次出现的键。我展示的代码确实输出了一个JSON对象数组,这也意味着您可能可以删除索引
字段(它是从数组中的顺序中隐式的)。是的-对于有序数组,我不再需要索引
,谢谢。
extern crate rustc_serialize;
use rustc_serialize::json;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::PathBuf;
#[derive(RustcEncodable)]
struct Item {
index: i32,
name: String,
path: String,
metadata_path: PathBuf,
}
fn write_review_queue(ordered_review_queue: &[Item]) -> io::Result<()> {
let mut buffer = try!(File::create("/tmp/output"));
write!(buffer, "{}", json::as_json(&ordered_review_queue))
}
fn main() {
let a = [Item { index: 0, name: "He\"llo".into(), path: "Good\\bye".into(), metadata_path: PathBuf::from(r#"C:\path\with'n\special"\chars"#)}];
write_review_queue(&a).expect("Failed");
}
[{"index":0,"name":"He\"llo","path":"Good\\bye","metadata_path":[67,58,92,112,97,116,104,92,119,105,116,104,39,110,92,115,112,101,99,105,97,108,34,92,99,104,97,114,115]}]
extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::PathBuf;
use std::collections::BTreeMap;
struct Item {
index: i32,
name: String,
path: String,
metadata_path: PathBuf,
}
impl ToJson for Item {
fn to_json(&self) -> Json {
let mut obj = BTreeMap::new();
obj.insert("Index".to_string(), self.index.to_json());
obj.insert("ReviewItemName".to_string(), self.name.to_json());
obj.insert("ReviewItemPath".to_string(), self.path.to_json());
obj.insert("MetadataPath".to_string(), self.metadata_path.to_string_lossy().to_json());
obj.to_json()
}
}
fn write_review_queue(ordered_review_queue: &[Item]) -> io::Result<()> {
let mut buffer = try!(File::create("/tmp/output"));
write!(buffer, "{}", json::as_json(&ordered_review_queue.to_json()))
}
fn main() {
let a = [Item { index: 0, name: "He\"llo".into(), path: "Good\\bye".into(), metadata_path: PathBuf::from(r#"C:\path\with'n\special"\chars"#)}];
write_review_queue(&a).expect("Failed");
}
[{"Index":0,"MetadataPath":"C:\\path\\with'n\\special\"\\chars","ReviewItemName":"He\"llo","ReviewItemPath":"Good\\bye"}]