저는 Rust를 처음 접했습니다.이 코드는 인공적인 학습 프로젝트의 일부입니다. 명심하십시오;)
튜플 컬렉션이 &[(i32, String, String, PathBuf)]
있습니다. 데이터를 JSON 파일에 쓰도록 설계된 함수로 전달됩니다.
문제 : PathBuf
를 a 로 변환 할 때 &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(())
}
출력의 예 :
{
"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를 생성하는 코드 MetadataPath
는 다음과 같습니다.
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_nonempty_metadata_fields
기능 :
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))
}
원래 디렉터리 경로 문자열을 다음과 같이 변경하면
let metadata_files = metadata_read::read_filenames_from_dir("C:/Dev/Temp/ReviewQueue/Metadata");
출력을 변경합니다. 예 :
{
"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"
}
}
그러나 그것은 여전히 옳지 않습니다.
질문
String
에 손으로 만들어진 JSON 형식, 어떻게의 경로 콘텐츠를받을 수 있나요 PathBuf
정방향 슬래시와 형식으로의 또는 백 슬래시를 탈출? API에 뭔가 빠졌나요?Json
데이터를 빌드하기 위해 객체를 사용해야합니까 (아마 더 신뢰할 수있을 것입니까)? 그렇다면 Json
객체 의 내용 을 파일 에 쓰는 일반적인 방법은 무엇 입니까?구조화 된 형식을 직접 생성하지 않는 것이 좋습니다. 결과적으로 출력 형식이 잘못 될 수 있기 때문입니다. 또한 출력에는 동일한 두 개의 키를 가진 객체가 있습니다. 유효 하지 않은 것은 아니지만 원하는 것이 아닐 수 있습니다.
이 경우 따옴표와 백 슬래시, 아포스트로피 및 앰퍼샌드를 피하려고 시도하면서 빠르게 벽에 부딪 힐 것입니다. 또한 마지막 항목을 손으로 추적해야합니다. 도서관이 열심히 일하게하십시오.
Rust를위한 두 가지 좋은 JSON 라이브러리가 있습니다 : rustc_serialize 와 serde .
첫 번째 단계는 데이터에 대한 실제 유형을 만드는 것입니다. 튜플은 훌륭하지만 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
추악한 방식으로 인쇄됩니다 .
[{"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]}]
PathBuf
s는 문자열 이 아님 을 아는 것이 중요합니다 . 특히, 이들은 플랫폼에 의존하는 추상화입니다. 유닉스 계열 시스템에서 경로는 UTF-8이 아니라 거의 비슷한 바이트 모음이고 Windows에서는 UCS-2에 가깝지만 UCS-2가 아닙니다.
귀하의 경우에 대해 진정한 UTF-8로 변환하는 데 적합한 손실 변환을 결정해야합니다. 표준 라이브러리에 내장 된 to_string_lossy
. 또한 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");
}
이것은 또한 객체의 키 이름을 바꿀 수있는 기회를 허용합니다 (이름이 나에게 매우 중복되는 것처럼 보임에도 불구하고).
[{"Index":0,"MetadataPath":"C:\\path\\with'n\\special\"\\chars","ReviewItemName":"He\"llo","ReviewItemPath":"Good\\bye"}]
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다