use crate::error::{Error, ErrorKind, Result}; use std; use std::fs::{remove_file, File}; use std::io::{Read, Write}; use std::path::Path; // Options and flags which can be used to configure how a file will be copied or moved. pub struct CopyOptions { /// Sets the option true for overwrite existing files. pub overwrite: bool, /// Sets the option true for skip existing files. pub skip_exist: bool, /// Sets buffer size for copy/move work only with receipt information about process work. pub buffer_size: usize, } impl CopyOptions { /// Initialize struct CopyOptions with default value. /// /// ```rust,ignore /// /// overwrite: false /// /// skip_exist: false /// /// buffer_size: 64000 //64kb /// ``` pub fn new() -> CopyOptions { CopyOptions { overwrite: false, skip_exist: false, buffer_size: 64000, //64kb } } /// Sets the option true for overwrite existing files. pub fn overwrite(mut self, overwrite: bool) -> Self { self.overwrite = overwrite; self } /// Sets the option true for skip existing files. pub fn skip_exist(mut self, skip_exist: bool) -> Self { self.skip_exist = skip_exist; self } /// Sets buffer size for copy/move work only with receipt information about process work. pub fn buffer_size(mut self, buffer_size: usize) -> Self { self.buffer_size = buffer_size; self } } impl Default for CopyOptions { fn default() -> Self { CopyOptions::new() } } /// A structure which stores information about the current status of a file that's copied or moved. . pub struct TransitProcess { /// Copied bytes on this time. pub copied_bytes: u64, /// All the bytes which should to copy or move. pub total_bytes: u64, } /// Copies the contents of one file to another. This function will also copy the permission /// bits of the original file to the destination file. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `from` path is not a file. /// * This `from` file does not exist. /// * The current process does not have the permission to access `from` or write `to`. /// /// # Example /// /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::copy; /// /// let options = CopyOptions::new(); //Initialize default values for CopyOptions /// copy("dir1/foo.txt", "dir2/bar.txt", &options)?; // Copy dir1/foo.txt to dir2/bar.txt /// /// ``` pub fn copy(from: P, to: Q, options: &CopyOptions) -> Result where P: AsRef, Q: AsRef, { let from = from.as_ref(); if !from.exists() { if let Some(msg) = from.to_str() { let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); err!(&msg, ErrorKind::NotFound); } err!( "Path does not exist or you don't have access!", ErrorKind::NotFound ); } if !from.is_file() { if let Some(msg) = from.to_str() { let msg = format!("Path \"{}\" is not a file!", msg); err!(&msg, ErrorKind::InvalidFile); } err!("Path is not a file!", ErrorKind::InvalidFile); } if !options.overwrite && to.as_ref().exists() { if options.skip_exist { return Ok(0); } if let Some(msg) = to.as_ref().to_str() { let msg = format!("Path \"{}\" exists", msg); err!(&msg, ErrorKind::AlreadyExists); } } Ok(std::fs::copy(from, to)?) } /// Copies the contents of one file to another file with information about progress. /// This function will also copy the permission bits of the original file to the /// destination file. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `from` path is not a file. /// * This `from` file does not exist. /// * The current process does not have the permission to access `from` or write `to`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::copy_with_progress; /// /// let options = CopyOptions::new(); //Initialize default values for CopyOptions /// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); /// /// // Copy dir1/foo.txt to dir2/foo.txt /// copy_with_progress("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; /// /// ``` pub fn copy_with_progress( from: P, to: Q, options: &CopyOptions, mut progress_handler: F, ) -> Result where P: AsRef, Q: AsRef, F: FnMut(TransitProcess), { let from = from.as_ref(); if !from.exists() { if let Some(msg) = from.to_str() { let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); err!(&msg, ErrorKind::NotFound); } err!( "Path does not exist or you don't have access!", ErrorKind::NotFound ); } if !from.is_file() { if let Some(msg) = from.to_str() { let msg = format!("Path \"{}\" is not a file!", msg); err!(&msg, ErrorKind::InvalidFile); } err!("Path is not a file!", ErrorKind::InvalidFile); } if !options.overwrite && to.as_ref().exists() { if options.skip_exist { return Ok(0); } if let Some(msg) = to.as_ref().to_str() { let msg = format!("Path \"{}\" exists", msg); err!(&msg, ErrorKind::AlreadyExists); } } let mut file_from = File::open(from)?; let mut buf = vec![0; options.buffer_size]; let file_size = file_from.metadata()?.len(); let mut copied_bytes: u64 = 0; let mut file_to = File::create(to)?; while !buf.is_empty() { match file_from.read(&mut buf) { Ok(0) => break, Ok(n) => { let written_bytes = file_to.write(&buf[..n])?; if written_bytes != n { err!("Couldn't write the whole buffer to file", ErrorKind::Other); } copied_bytes += n as u64; let data = TransitProcess { copied_bytes, total_bytes: file_size, }; progress_handler(data); } Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => {} Err(e) => return Err(::std::convert::From::from(e)), } } Ok(file_size) } /// Moves a file from one place to another. This function will also copy the permission /// bits of the original file to the destination file. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `from` path is not a file. /// * This `from` file does not exist. /// * The current process does not have the permission to access `from` or write `to`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::move_file; /// /// let options = CopyOptions::new(); //Initialize default values for CopyOptions /// move_file("dir1/foo.txt", "dir2/foo.txt", &options)?; // Move dir1/foo.txt to dir2/foo.txt /// /// ``` pub fn move_file(from: P, to: Q, options: &CopyOptions) -> Result where P: AsRef, Q: AsRef, { let mut is_remove = true; if options.skip_exist && to.as_ref().exists() && !options.overwrite { is_remove = false; } let result = copy(&from, to, options)?; if is_remove { remove(from)?; } Ok(result) } /// Moves a file from one place to another with information about progress. /// This function will also copy the permission bits of the original file to the /// destination file. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `from` path is not a file. /// * This `from` file does not exist. /// * The current process does not have the permission to access `from` or write `to`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::move_file; /// /// let options = CopyOptions::new(); //Initialize default values for CopyOptions /// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); /// /// // Move dir1/foo.txt to dir2/foo.txt /// move_file("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; /// /// ``` pub fn move_file_with_progress( from: P, to: Q, options: &CopyOptions, progress_handler: F, ) -> Result where P: AsRef, Q: AsRef, F: FnMut(TransitProcess), { let mut is_remove = true; if options.skip_exist && to.as_ref().exists() && !options.overwrite { is_remove = false; } let result = copy_with_progress(&from, to, options, progress_handler)?; if is_remove { remove(from)?; } Ok(result) } /// Removes a file from the filesystem. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * The current process does not have the permission to access `path`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::remove; /// /// remove("foo.txt" )?; // Remove foo.txt /// /// ``` pub fn remove

(path: P) -> Result<()> where P: AsRef, { if path.as_ref().exists() { Ok(remove_file(path)?) } else { Ok(()) } } /// Read file contents, placing them into `String`. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `path` is not a file. /// * This `path` file does not exist. /// * The current process does not have the permission to access `path`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::read_to_string; /// /// let file_content = read_to_string("foo.txt" )?; // Get file content from foo.txt /// println!("{}", file_content); /// /// ``` pub fn read_to_string

(path: P) -> Result where P: AsRef, { let path = path.as_ref(); if path.exists() && !path.is_file() { if let Some(msg) = path.to_str() { let msg = format!("Path \"{}\" is not a file!", msg); err!(&msg, ErrorKind::InvalidFile); } err!("Path is not a file!", ErrorKind::InvalidFile); } let mut file = File::open(path)?; let mut result = String::new(); file.read_to_string(&mut result)?; Ok(result) } /// Write `String` content into file. /// /// # Errors /// /// This function will return an error in the following situations, but is not limited to just /// these cases: /// /// * This `path` is not a file. /// * This `path` file does not exist. /// * The current process does not have the permission to access `path`. /// /// # Example /// ```rust,ignore /// extern crate fs_extra; /// use fs_extra::file::read_to_string; /// /// write_all("foo.txt", "contents" )?; // Create file foo.txt and send content inside /// /// ``` pub fn write_all

(path: P, content: &str) -> Result<()> where P: AsRef, { let path = path.as_ref(); if path.exists() && !path.is_file() { if let Some(msg) = path.to_str() { let msg = format!("Path \"{}\" is not a file!", msg); err!(&msg, ErrorKind::InvalidFile); } err!("Path is not a file!", ErrorKind::InvalidFile); } let mut f = File::create(path)?; Ok(f.write_all(content.as_bytes())?) }