2015-06-15 4 views
6

मैं मुसीबत एक फाइल करने के लिए Vec<u16> सामग्री लिख रही:फ़ाइल में 'Vec <u16>' सामग्री लिखने का सही तरीका क्या है?

use std::fs::File; 
use std::io::{Write, BufWriter}; 
use std::mem; 

#[derive(Debug, Copy, Clone, PartialEq)] 
pub enum ImageFormat { 
    GrayScale, 
    Rgb32, 
} 

#[derive(Debug, Copy, Clone, PartialEq)] 
pub struct ImageHeader { 
    pub width: usize, 
    pub height: usize, 
    pub format: ImageFormat, 
} 

pub struct Image { 
    pub header: ImageHeader, 
    pub data: Vec<u16>, 
} 

fn write_to_file(path: &str, img: &Image) -> std::io::Result<()> { 
    let f = try!(File::create(path)); 
    let mut bw = BufWriter::new(f); 
    let slice = &img.data[..]; 
    println!("before length: {}", slice.len()); 
    let sl: &[u8]; 
    unsafe { 
     sl = mem::transmute::<&[u16], &[u8]>(slice); 
    } 
    println!("after length: {}", sl.len()); 
    try!(bw.write_all(sl)); 
    return Ok(()); 
} 

fn main() {} 

write_all() के बाद से एक &[u8] के लिए पूछता है, मैं &[u8] को &[u16] का असुरक्षित रूपांतरण कर रहा हूँ। चूंकि रूपांतरण स्लाइस लम्बाई को बदलता नहीं है (slice.len() और sl.len() समान मान हैं), छवि डेटा का केवल आधा फ़ाइल में आउटपुट है।

यदि बेहतर मुझे किसी भी असुरक्षित रूपांतरण या प्रतिलिपि की आवश्यकता नहीं है तो यह बेहतर होगा।

उत्तर

7

यह सीधे ऐसा करने के लिए आप का उपयोग करने के std::slice::from_raw_parts() चाहते हैं:

use std::slice; 
use std::mem; 

fn main() { 
    let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6]; 
    println!("u16s: {:?}", slice_u16); 

    let slice_u8: &[u8] = unsafe { 
     slice::from_raw_parts(
      slice_u16.as_ptr() as *const u8, 
      slice_u16.len() * mem::size_of::<u16>(), 
     ) 
    }; 

    println!("u8s: {:?}", slice_u8); 
} 

यह unsafe क्योंकि from_raw_parts() की आवश्यकता होती है गारंटी नहीं दे सकते कि आप केवल इसे करने के लिए एक वैध सूचक पारित कर सकते हैं, और यह भी स्लाइस बना सकते हैं मनमाना जीवन भर के साथ।

हालांकि, यह दृष्टिकोण न केवल संभावित रूप से असुरक्षित है, यह पोर्टेबल भी नहीं है। जब आप एक बाइट से बड़े पूर्णांक के साथ काम करते हैं, तो अंतहीनता के मुद्दे तुरंत उत्पन्न होते हैं। यदि आप x86 मशीन पर इस तरह से एक फ़ाइल लिखते हैं, तो आप एआरएम मशीन पर कचरा पढ़ लेंगे। उचित तरीके से byteorder जो आप endianness स्पष्ट रूप से निर्दिष्ट करने की अनुमति की तरह पुस्तकालयों का उपयोग करने के लिए है:

extern crate byteorder; 

use byteorder::{WriteBytesExt, LittleEndian}; 

fn main() { 
    let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6]; 
    println!("u16s: {:?}", slice_u16); 

    let mut result: Vec<u8> = Vec::new(); 
    for &n in slice_u16 { 
     let _ = result.write_u16::<LittleEndian>(n); 
    } 

    println!("u8s: {:?}", result); 
} 

ध्यान दें कि मैं Vec<u8> यहां इस्तेमाल किया है, लेकिन यह Write लागू करता है, और write_u16() और WriteBytesExt विशेषता से अन्य तरीकों से किसी पर परिभाषित कर रहे हैं Write, इसलिए आप इन तरीकों का उपयोग सीधे BufWriter पर कर सकते हैं, उदाहरण के लिए।

हालांकि यह स्मृति के एक टुकड़े को दोबारा परिभाषित करने से थोड़ा कम कुशल हो सकता है, यह सुरक्षित और पोर्टेबल है।

+0

धन्यवाद! मैंने 'स्लाइस :: from_raw_parts()' का उपयोग करने की आपकी विधि की कोशिश की और यह पूरी तरह से काम किया। – rillomas

5

मैं क्रमबद्धता के लिए मौजूदा पुस्तकालयों उपयोग करने की अनुशंसा ऐसे serde और bincode के रूप में:

extern crate bincode; 
extern crate serde; 
#[macro_use] 
extern crate serde_derive; 

use std::error::Error; 

#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)] 
pub enum ImageFormat { 
    GrayScale, 
    Rgb32, 
} 

#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)] 
pub struct ImageHeader { 
    pub width: usize, 
    pub height: usize, 
    pub format: ImageFormat, 
} 

#[derive(Serialize, Deserialize)] 
pub struct Image { 
    pub header: ImageHeader, 
    pub data: Vec<u16>, 
} 

impl Image { 
    fn save_to_disk(&self, path: &str) -> Result<(), Box<Error>> { 
     use std::fs::File; 
     use std::io::Write; 
     let bytes: Vec<u8> = try!(bincode::serialize(self, bincode::Infinite)); 
     let mut file = try!(File::create(path)); 
     file.write_all(&bytes).map_err(|e| e.into()) 
    } 
} 

fn main() { 
    let image = Image { 
     header: ImageHeader { 
      width: 2, 
      height: 2, 
      format: ImageFormat::GrayScale, 
     }, 
     data: vec![0, 0, 0, 0], 
    }; 

    match image.save_to_disk("image") { 
     Ok(_) => println!("Saved image to disk"), 
     Err(e) => println!("Something went wrong: {:?}", e.description()), 
    } 
} 
+1

धन्यवाद! मैंने bincode + rustc-serialize का उपयोग करने की आपकी विधि भी कोशिश की, और व्यक्तिगत रूप से मैं इस विधि को कच्चे डेटा को फ़ाइल में डंप करने से अधिक पसंद करता हूं (कोई 'असुरक्षित' नहीं, अंतहीनता के बारे में चिंता करने की आवश्यकता नहीं है)। मैं व्लादिमीर के जवाब को स्वीकार कर रहा हूं क्योंकि यह विषय पर अधिक था, लेकिन जैसा कि आपने कहा है कि धारावाहिकरण का उपयोग करना शायद बेहतर तरीका है। – rillomas

संबंधित मुद्दे

 संबंधित मुद्दे