0

So I would like to copy files to a specific folder based on a certain part in their name. For your overview I put my folder structure below. In the folders D0 and D1 I have multiple files (as example I put names of two files here) and the folders Weather and Temperature. I would like to move the .txt files to either the folder Weather or Temperature depending on whether the file name has Weather in its name or Temperature (see what I would like).

Current situation:

main Directory
|
|___ Experiment
        ├── D0
           ├── temperature
        │  └── Weather
           |__ Weather 100.txt
           |__ Temperature 100.txt
        └── D1
           ├── temperature
           └── weather
           |__ Weather 100.txt
           |__ Temperature 100.txt

What I would like:

main Directory
    |
    |___ Experiment
            ├── D1
               ├── Weather
                        |__Weather 100.txt
               └── Temperature
                        |__ Temperature 100.txt

I tried to do it in steps, so first the D0 to move the Weather, and then go further with D0 and move the Temperature files, D1 Weather and lastly the D1 Temperature files.

The problem however is twofold. The first obstacle is that although I get a list of files with Weather, once I want to copy it to a new directory I get an error saying that it cannot copy the file because there is no such file or directory. What is wrong with my code? The second problem is that the code is not so efficient if I want to do it like this, because I have to run the code four times (and even more if there are more than two maps (D3, D4 etc.). Is there a way to make the code more efficient, so it can do it all at once?

2 Answers2

1

Here is a function that first gets the directories in ./Experiment and then applies a function fun to each of them, moving the files it finds to sub-directories sharing part of the name.

fun <- function(path){
  files <- list.files(path = path)
  files <- file.path(path, files)
  info <- file.info(files)
  dirs <- files[info$isdir]
  fls <- files[!info$isdir]
  out <- lapply(dirs, function(d){
    i <- grep(basename(d), fls, ignore.case = TRUE)
    if(length(i)){
      to <- file.path(d, basename(fls[i]))
      tryCatch(
        file.rename(fls[i], to = to),
        error = function(e) e
      )
    } else NULL
  })
  out
}

setwd('~/tmp/Experiment')
d <- list.dirs(recursive = FALSE)
sapply(d, fun)
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • Hi, thank you for your suggestion. This code is doing part of the job. The files with FITC are moved to their corresponding map. However, files with brightfield in their name are not moved to the their corresponding folder. As output I get ./D0 ./D1 [1,] Null Null [2,] logical ,18 Logical, 40. Is their a solution for this? – alexdegrote1995 Apr 18 '21 at 06:25
  • @alexdegrote1995 Maybe now that I have added `ignore.case = TRUE` to `grep`? – Rui Barradas Apr 18 '21 at 06:30
0

The following function checks if the filename corresponds to the destination directory (to) and if not:

  • creates the new destination directory
  • moves the file to the directory

The function is called by lapply for each destination :

library(stringr)
#Get all files
path <- 'C:/temp/experiment'
files <- list.files(path= path, recursive = TRUE)

move.file <- function(filename,to = 'Brightfield') {
  fromdir <- dirname(filename)
  rootdir <- dirname(fromdir)
  filebase <- basename(filename)
  # File not in right directory
  if (str_detect(filebase, regex(to, ignore_case = TRUE))&
      !str_detect(fromdir, regex(to, ignore_case = TRUE))) {
    dir.create(file.path(rootdir,to),showWarnings = F)
    file.rename(from = file.path(path,filename),
              to = file.path(path,rootdir,to,filebase))
  } else {F}
}

lapply(files, move.file, to='Brightfield')
lapply(files, move.file, to='FITC')
Waldi
  • 39,242
  • 6
  • 30
  • 78
  • Hi, thank you for your suggestion. If I run your code I get an error at the lapply function that says that object "B" is not found. What is B exactly? – alexdegrote1995 Apr 18 '21 at 06:13
  • Sorry, this was a test subset. Just use the file list, see my edit. – Waldi Apr 18 '21 at 06:49
  • Hi, I also tried this code, but when I run the code I get an error saying that "object" from is not found. Why does it say this error? – alexdegrote1995 May 06 '21 at 07:41
  • @alexdegrote1995, thanks for your feedback, there was a typo in `rootdir <- dirname(fromdir)`, corrected – Waldi May 06 '21 at 07:46