文章目录

  • 0. 新建文件夹
  • 1. os.walk(遍历多层文件夹)
  • 1.1 一般用法
  • 1.2 访问特定层级/深度的文件夹
  • 1.3 排除os.walk中部分文件夹的迭代
  • 1.4 统计多层文件结构的文件/文件夹数量
  • 2. os.listdir
  • 3. pathlib.Path.glob
  • 4. 判断一个文件是普通文件还是文件夹
  • 5. 重命名,移动/复制文件
  • 5.1 os.rename
  • 5.2 shutil.move
  • 5.3 shutil.copy
  • 6. 复制文件夹


0. 新建文件夹

os.makedirs(new_folder,exist_ok=True)

1. os.walk(遍历多层文件夹)

1.1 一般用法

我现在有以下文件夹结构,为了处理.dcm文件,需要在LCTSC-Test-S1-101 文件的基础上,访问到存储.dcm文件所在的文件夹。

~/Downloads/LCTSC/LCTSC-Test-S1-101 » tree -L 3
.
└── 03-03-2004-NA-NA-08186
    ├── 1.000000-NA-56597
    │   └── 1-1.dcm
    └── NA-79262
        ├── 1-001.dcm
        ├── 1-002.dcm

因此考虑使用os.walk,示例如下:

for root, dirs, files in os.walk(nii_name_path[0], topdown=True):
    for name in files[:3]:  # 打印文件
        print(os.path.join(root, name))
    for name in dirs:  # 打印所有目录/文件夹
        print(os.path.join(root, name))

# 结果如下        
> ../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/1.000000-.simplified-23857
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/211.000000-Ave-IP10 0102030405060708090-83140
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/1.000000-.simplified-23857/1-1.dcm
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/211.000000-Ave-IP10 0102030405060708090-83140/21-008.dcm
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/211.000000-Ave-IP10 0102030405060708090-83140/13-002.dcm
../LCTSC/LCTSC-Train-S2-008/01-09-1999-NA-4DCT THORAX-15057/211.000000-Ave-IP10 0102030405060708090-83140/03-002.dcm

参考:

1.2 访问特定层级/深度的文件夹

根据参考内容进行整理,没有特别高档的方法,都是walk的结果进行一些简单的判断,让它不至于输出。

解决1

来自Github wiki:A python function to do an os.walk(), but only to a certain depth. A negative depth indicates full depth.

import os

def walklevel(path, depth = 1):
    """It works just like os.walk, but you can pass it a level parameter
       that indicates how deep the recursion will go.
       If depth is 1, the current directory is listed.
       If depth is 0, nothing is returned.
       If depth is -1 (or less than 0), the full depth is walked.
    """
    if depth < 0:
        for root, dirs, files in os.walk(path):
            yield root, dirs[:], files
        return
    elif depth == 0:
        return
        
    base_depth = path.rstrip(os.path.sep).count(os.path.sep)
    for root, dirs, files in os.walk(path):
        yield root, dirs[:], files
        cur_depth = root.count(os.path.sep)
        if base_depth + depth <= cur_depth:
            del dirs[:]

解决2
来自Stack Overflow:os.walk without digging into directories below

import os

def walklevel(some_dir, level=1):
    some_dir = some_dir.rstrip(os.path.sep)
    assert os.path.isdir(some_dir)
    num_sep = some_dir.count(os.path.sep)
    for root, dirs, files in os.walk(some_dir):
        yield root, dirs, files
        num_sep_this = root.count(os.path.sep)
        if num_sep + level <= num_sep_this:
            del dirs[:]

参考:

1.3 排除os.walk中部分文件夹的迭代

参考Stack Overflow:Excluding directories in os.walk

只需要加一个判断即可,例如:

exclude = set(['New folder', 'Windows', 'Desktop'])
for root, dirs, files in os.walk(top, topdown=True):
    dirs[:] = [d for d in dirs if d not in exclude]

1.4 统计多层文件结构的文件/文件夹数量

import os
base_dir="XXX"

all_files=[]
all_dir=[]
for root, dirs, files in os.walk(base_dir, topdown=True):
    for name in dirs:
        all_dir.append(os.path.join(root, name))
    for name in files:
        if "DS_Store" not in name:  # 如果是mac,排除.DS_Store文件问题
            all_files.append(os.path.join(root, name))
print(len(all_dir))
print(len(all_files))

2. os.listdir

import os
base_dir="XXX"
file_list=os.listdir(base_dir)

3. pathlib.Path.glob

根据Stack Overflow:How to use glob() to find files recursively?

例如,我想找到一个文件夹中所有以LCTSC开头的文件夹,文件结构如下:

~/Downloads/LCTSC » tree -L 1                 
.
├── LCTSC-Test-S1-101
├── LCTSC-Test-S1-102
├── LCTSC-Test-S1-103
├── LCTSC-Test-S1-104
├── LCTSC-Test-S1-201
├── LCTSC-Test-S1-202
├── ...
└── LICENSE

可以:

import glob
nii_name_path=glob.glob('../LCTSC/LCTSC*')

glob函数不像listdir一样,有一个单独的路径参数,它只接受一个参数,在指定base_dir的同时就要写好筛选文件的正则表达式,如上。

参考:

4. 判断一个文件是普通文件还是文件夹

  • os.path.exists(path),判断这个路径是否正确,这个路径可以是一个文件夹/文件或者软连接(快捷方式)等
  • os.path.isfile(path),如果路径是一个普通文件或者指向一个文件的链接,则返回true
  • os.path.isdir(path),如果路径是一个文件夹或者指向文件夹的链接,则返回true

例如:

import os.path

if os.path.isfile('filename.txt'):
    print ("File exist")
else:
    print ("File not exist")

参考:

5. 重命名,移动/复制文件

5.1 os.rename

示例

os.rename("../a/123.txt","../b/12.txt")

语法
将src参数所代表的文件或者目录重命名为dst,如果dst已经存在,会抛出一个OSError子类的错误,执行失败。

  • 在Windows平台上,如果dst存在,则总是会抛出FileExistsError
  • 在Unix上,
  • 如果scr是一个文件,dst是一个目录(反之也可以),则会分别抛出一个IsADirectoryErrorNotADirectoryError错误。
  • 如果两个都是目录,dst为空,则dst会被静默替换;如果dst一个非空的目录,则会抛出OSError错误.
  • 如果两个都是文件,如果用户具有权限,则dst将会被静默替换。如果 src 和 dst 在不同的文件系统上,该操作可能会在某些 Unix上失败。 如果成功,重命名将是一个原子操作(这是 POSIX 要求)。
  • 此函数可以支持指定 src_dir_fd 和 dst_dir_fd 以提供相对于目录描述符的路径。

文件夹内操作相当于直接重命名,跨文件夹操作相当于移动文件并重命名(没有复制,直接移动)

参考:

5.2 shutil.move

示例

import shutil
shutil.move('file.txt', 'path/to/new/directory/')

语法解释

shutil.move(src, dst, copy_function=copy2)
  • 迭代的将一个文件或者目录(scr参数)移动到另一个地址(dst参数),返回dst
  • 如果dst是一个已有的目录,则src会直接移动到这个目录中。
  • 如果dst已经存在但不是一个目录,其会根据os.rename()的语法来决定是否覆盖
  • 如果dst位于当前的文件系统中,则直接使用os.rename()(即src和dst在同一目录中)。
  • 否则在其他情况时,src会使用copy_function复制到dst,然后被删除。
  • 如果是软链接,则会有一个指向src代表的目标的新链接被创建,同时scr会被删除
  • copy_function是一个可以自己指定函数的参数,一般不使用

shutil.move与os.rename的区别

  • 从调用上就可以看出明显的区别。
os.rename("../a/123.txt","../b/12.txt")
shutil.move('file.txt', 'path/to/new/directory/')
  • shutil.move的第二个参数只能是个目录
  • os.rename可以在重命名的时候捎带就移动个位置

参考:

5.3 shutil.copy

shutil.copy(src, dst, *, follow_symlinks=True)

示例

import shutil
shutil.copy(oldName, newName)

os.rename("../a/123.txt","../b/12.txt")
shutil.copy("../a/123.txt","../b/12.txt")
"""
二者的区别在于,
rename是移动,src中的文件会消失
而copy是复制,scr中的文件依然会保留
"""

copy可以复制捎带重命名

参考

6. 复制文件夹