Search code examples
rcopysubdirectorydirectory-structureimage-compression

How to copy and compress files in R while keeping subfolder structure


I have a hard drive filled with images in several folders. I would like to copy and compress these images, but keeping the subfolders tree structure. I struggle with creating the new folders, based on the original structure. My first approach was something like:

    ## LISTING ALL FILES
    list.of.files <- list.files(path = "C:/Download/Photos/Site_Z", full.names = TRUE, recursive = TRUE)
    
    ## CREATE THE NEW DIRECTORY WHERE THE FILES SHOULD GO
    list.of.dest.files <- gsub("Site_Z", "Copy_Z", list.of.files)
    
    ## GET UNIQUE DIRECTORIES
    UniqueDirs <- unique(dirname(list.of.dest.files))
    
## EXAMPLE OUTPUT DIRS
##C:/Download/Photos/Site_Z/202008/Elephant
##C:/Download/Photos/Site_Z/202008/Empty
##C:/Download/Photos/Site_Z/202007/Lion
##C:/Download/Photos/Site_Z/202007/Empty

    ## LOOP THROUGH THE UNIQUE DIRS AND CREATE THEM
    for (i in 1:length(UniqueDirs)){
      dir.create(path = UniqueDirs[i])
    }

This does not work, because some of the directories are not created yet. I think the steps would be something like this:

  1. Identify the original folder and subfolder structure
  2. Copy the folders (without any images) to the desired location
  3. Loop through every subfolder to load the images, compress them, and export them to the new location.

I used the loop here to load the images in batches, rather than all the images at once. I'm using a simple laptop, so doing smaller batches at the time is probably the best way forward. I believe the compressing-part is not that difficult with packages like 'magick' or similar. Would some have any idea how to create a workflow in R for the above steps?


Solution

  • I managed to get the code running with the help of akrun. Here's the full code, also including the compressing part.

    1. LOAD PACKAGES

    library(magick)
    library(purrr)
    library(furrr)
    

    2. SET MAIN FOLDER

    Directory_Folder <- "./Data"  ## MAKE SURE TO INCLUDE THE FINAL FORWARD SLASH
    Cameras <- list.dirs("./Data", full.names = FALSE, recursive = FALSE)
    

    3. SET NEW LOCATION

    New_Directory <- "./Compressed"     ## MAKE SURE TO INCLUDE THE FINAL FORWARD SLASH
    

    4. LIST ALL DIRECTORIES

    list.of.files <- list.files(path = "./Data", full.names = TRUE, recursive = TRUE)
    

    RECOMMENDED

    # REMOVE THE '#' OF THE LINE BELOW IF YOU WANT TO TEST THE SCRIPT ON A SMALLER SUBSET
    #list.of.files <- sample(list.of.files, 100)  ## TAKES A RANDOM SAMPLE OF 100 IMAGES 
    

    5. CREATE THE MAIN MAIN FOLDER ON DESKTOP TO COPY THE FILES TO

    list.of.dest.files <- gsub(Directory_Folder, New_Directory, list.of.files)
    

    6. MAKE SURE EACH DIRECTORY AND SUBFOLDER IS LISTED ONCE

    NewDirs <- unique(dirname(list.of.dest.files))
    

    7. LOOP THROUGH THE ALL FOLDERS AND SUBFOLDERS TO CREATE THEM

    for (i in 1:length(NewDirs)){
      if(!dir.exists(path = NewDirs[i])) 
        dir.create(path = NewDirs[i], recursive = TRUE)
    }
    

    8. FUNCTION FOR READING, RESIZING, AND WRITING IMAGES

    MyFun <- function(i) {
      
      new.file.name <- gsub(Directory_Folder, New_Directory, i)
      
      magick::image_read(i) %>%  ## IMPORT PHOTOS INTO R
                image_scale("400") %>%  ## IMAGE RE-SCALING
                image_write(path = new.file.name)
      gc()
    }
    

    9. SET UP MULTI-CORES

    no_cores <- availableCores() - 1
    future::plan(multisession, workers = no_cores)
    

    10. RUN FUNCTION ON ALL FILES

    future_map(list.of.files, MyFun)   ## THIS MIGHT TAKE A WHILE