Reduce allocations in `fs::copy_files_except_ext`

Above mentioned function copies files (recursively) from a source to a
destination directory. For that, file/directory paths have to be created
repeatedly. This allocates as directory and file names are concatenated
into an owning path structure.

The number of allocations can be reduced by creating file/directory
paths only once and borrowing them instead of cloning/recreating them.

In bigger projects, this reduces execution time noticeably. Please note
that file system operations are dominant from performance POV.
This commit is contained in:
Johannes Gloeckle 2024-04-05 09:50:14 +02:00
parent bd323fb930
commit c144c26dcf
1 changed files with 19 additions and 52 deletions

View File

@ -72,14 +72,12 @@ pub fn create_file(path: &Path) -> Result<File> {
/// Removes all the content of a directory but not the directory itself /// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<()> { pub fn remove_dir_content(dir: &Path) -> Result<()> {
for item in fs::read_dir(dir)? { for item in fs::read_dir(dir)?.flatten() {
if let Ok(item) = item { let item = item.path();
let item = item.path(); if item.is_dir() {
if item.is_dir() { fs::remove_dir_all(item)?;
fs::remove_dir_all(item)?; } else {
} else { fs::remove_file(item)?;
fs::remove_file(item)?;
}
} }
} }
Ok(()) Ok(())
@ -108,72 +106,41 @@ pub fn copy_files_except_ext(
} }
for entry in fs::read_dir(from)? { for entry in fs::read_dir(from)? {
let entry = entry?; let entry = entry?.path();
let metadata = entry let metadata = entry
.path()
.metadata() .metadata()
.with_context(|| format!("Failed to read {:?}", entry.path()))?; .with_context(|| format!("Failed to read {entry:?}"))?;
let entry_file_name = entry.file_name().unwrap();
let target_file_path = to.join(entry_file_name);
// If the entry is a dir and the recursive option is enabled, call itself // If the entry is a dir and the recursive option is enabled, call itself
if metadata.is_dir() && recursive { if metadata.is_dir() && recursive {
if entry.path() == to.to_path_buf() { if entry == to.as_os_str() {
continue; continue;
} }
if let Some(avoid) = avoid_dir { if let Some(avoid) = avoid_dir {
if entry.path() == *avoid { if entry == *avoid {
continue; continue;
} }
} }
// check if output dir already exists // check if output dir already exists
if !to.join(entry.file_name()).exists() { if !target_file_path.exists() {
fs::create_dir(&to.join(entry.file_name()))?; fs::create_dir(&target_file_path)?;
} }
copy_files_except_ext( copy_files_except_ext(&entry, &target_file_path, true, avoid_dir, ext_blacklist)?;
&from.join(entry.file_name()),
&to.join(entry.file_name()),
true,
avoid_dir,
ext_blacklist,
)?;
} else if metadata.is_file() { } else if metadata.is_file() {
// Check if it is in the blacklist // Check if it is in the blacklist
if let Some(ext) = entry.path().extension() { if let Some(ext) = entry.extension() {
if ext_blacklist.contains(&ext.to_str().unwrap()) { if ext_blacklist.contains(&ext.to_str().unwrap()) {
continue; continue;
} }
} }
debug!( debug!("Copying {entry:?} to {target_file_path:?}");
"creating path for file: {:?}", copy(&entry, &target_file_path)?;
&to.join(
entry
.path()
.file_name()
.expect("a file should have a file name...")
)
);
debug!(
"Copying {:?} to {:?}",
entry.path(),
&to.join(
entry
.path()
.file_name()
.expect("a file should have a file name...")
)
);
copy(
entry.path(),
&to.join(
entry
.path()
.file_name()
.expect("a file should have a file name..."),
),
)?;
} }
} }
Ok(()) Ok(())