如何在R中列出.files()直到n级深度查询

mftmpeh8  于 2023-10-13  发布在  其他
关注(0)|答案(3)|浏览(131)

我有一个非常复杂的文件夹组织,这里是它的简化版本。

|--Folder0 --- Folder0.1
       |
home---|--Folder1 --- Folder1.1 --- Folder1.2
       |
       |--Folder2 --- Folder2.1

我想从第二级文件夹(Folder0.1,Folder1.1,Folder2.1)列出所有.xlsx文件。
任何帮助真的很感激。

**请不要将文件夹的名称视为理所当然。为了简单起见,我这样称呼他们。**他们的名字是随机的。

ffx8fchx

ffx8fchx1#

list.files(recursive=)不允许立即限制,我建议三种路径:
1.获取全部,在文件分隔符(通常为/)上拆分,并限制列表。

allfiles <- list.files(".", full.names = TRUE, recursive = TRUE)
under5 <- allfiles[ lengths(strsplit(allfiles, "/")) < 6 ]

由于它可能以"."开头,因此您可能需要比您认为的更多的一个。在这里尝试使用6以获得您所需要的。
1.如果它只有几个深度,那么手动构造目录列表并完全禁用recursive

dir1 <- list.dirs(".", recursive=FALSE)
dir2 <- list.dirs(dir1, recursive=FALSE)
dir3 <- list.dirs(dir2, recursive=FALSE)
dir4 <- list.dirs(dir3, recursive=FALSE)
allfiles <- setdiff(list.files(c(dir1, dir2, dir3)), c(dir1, dir2, dir3))

(不可否认的是,测试不足,不太棒,但这是一个方法的开始。
1.使用system("find . -maxdepth 5 -type f", intern=TRUE)或类似的方法来生成文件名。

dw1jzc5e

dw1jzc5e2#

调用list.files(recursive = TRUE)然后过滤结果是一种有效的方法,但是它容易出错,并且不能很好地随递归所经过的文件系统树的大小和深度而扩展。
我会考虑调用你的操作系统提供的命令行实用程序之一,你可以通过R的systemsystem2来做。例如,在Unix上,您可以简单地执行以下操作:

system("find . -maxdepth n -type f -regex '.*[.]xlsx'", intern = TRUE)

n替换为你想要的递归深度。这种方法的一个优点是find是高度优化的,并且比list.files有更多的选项。
另一个可扩展的选择是编写自己的递归函数,在您想要的地方停止。下面是一个可能性,你可能应该比我测试更多。

lf <- function(path = ".", maxdepth = 0L, pattern = NULL, all.files = FALSE, include.dirs = FALSE) {
    fn <- list.files(path, pattern = pattern, all.files = all.files, full.names = TRUE, no.. = TRUE)
    dn <- list.dirs(path, full.names = TRUE, recursive = FALSE)
    fn <- fn[match(fn, dn, 0L) == 0L]
    if (!all.files) {
        dn <- dn[grepl("^[^.]", basename(dn))]
    }
    if (length(dn) == 0L) {
        return(fn)
    }
    if (maxdepth < 1L) {
        if (include.dirs) {
            return(c(fn, dn))
        } else {
            return(fn)
        }
    }
    l <- lapply(dn, lf, maxdepth = maxdepth - 1L, pattern = pattern, all.files = all.files, include.dirs = include.dirs)
    if (include.dirs) {
        l <- Map(c, dn, l, USE.NAMES = FALSE) 
    }
    c(fn, unlist(l, FALSE, FALSE))
}

然后又道:

lf(".", maxdepth = n, pattern = "[.]xlsx$")

再次将n替换为所需的递归深度。

50few1ms

50few1ms3#

在受到这个问题的启发后,我想加入一个类似于Mikael Jagan解决方案的解决方案:list files recursive up to a certain level in R我做了一个函数来从特定的深度列出文件夹。

list_dir_n_depth <- function(path_use, depth_keep = 1){
    # Initiate
    path_list = list()
    level = 1
    path_list[[level]] = path_use # initiate first level 
    q = path_list[[level]]

    # loop it till no child level left, or reached depth_keep
    while(length(q) > 0 & level < depth_keep){
        level = level + 1 # Advance one level to add all the child nodes
        path_list[[level]] = vector() # initiate child list

        for(i in seq(length(q), 1, -1)){ # when there are more than one item, collect all the child for next level 
            all_childs_this_dir = list.dirs(q[[i]], recursive = FALSE) # get all childs
            path_list[[level]] = c(path_list[[level]], all_childs_this_dir) # Add to current level list
        }

        # Get all items from next level
        q = path_list[[level]]
        
    }
    # retrun the level to print
    if(depth_keep > length(path_list)) return(NULL) else return(path_list[[depth_keep]])
}

例如,我有一个文件夹结构设置列表,

.
├── folder1
│   ├── fd11
│   │   ├── file1.xlsx
│   │   └── file2.xlsx
│   ├── fd12
│   │   ├── file121.xlsx
│   │   └── file1.xlsx
│   ├── fd13
│   ├── fileA.xlsx
│   └── fileB.xlsx
├── folder2
│   ├── fd21
│   │   ├── file23.xlsx
│   │   └── file33.xlsx
│   └── fd22
└── folder3
    ├── df31
    ├── df32
    ├── df33
    │   ├── file34.xlsx
    │   └── file36.xlsx
    └── df34

使用此函数得到list_dir_n_depth("PATH/TO/YOUR/DIR", depth_keep = 3)

[1] "/folder3/df31" "/folder3/df32" "/folder3/df33" "/folder3/df34"
[5] "/folder2/fd21" "/folder2/fd22" "/folder1/fd11" "/folder1/fd12"
[9] "/folder1/fd13"

和组合得到所有的xlsx下的文件夹级别3

list_dir_n_depth("PATH/TO/YOUR/DIR", depth_keep = 3) %>% list.files(pattern = 'xlsx', full.names = F)

[1] "file1.xlsx"   "file1.xlsx"   "file121.xlsx" "file2.xlsx"   "file23.xlsx"
[6] "file33.xlsx"  "file34.xlsx"  "file36.xlsx"

为了让xlsx更上一层楼

list_dir_n_depth("PATH/TO/YOUR/DIR", depth_keep = 2) %>% list.files(pattern = 'xlsx', full.names = F)

[1] "fileA.xlsx" "fileB.xlsx"

注意,在list.files中设置full.names = T以获取文件的完整路径
例如,如果只想保留fd21文件夹中的xlsx,可以从stringr中选择grepstr_subset来进一步过滤结果吗?

# str_subset
list_dir_n_depth("PATH/TO/YOUR/DIR", depth_keep = 3) %>% 
    list.files(pattern = 'xlsx', full.names = T)  %>% 
    str_subset('fd21')

# grep
list_dir_n_depth(TEST, depth_keep = 3) %>% 
    list.files(pattern = 'xlsx', full.names = T)  %>% 
    .[grep('fd21', .)]

[1] "PATH/TO/YOUR/DIR/folder2/fd21/file23.xlsx"
[2] "PATH/TO/YOUR/DIR/folder2/fd21/file33.xlsx"

相关问题