文章目录
- 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
参考:
- 菜鸟教程:Python os.walk() 方法
- GeeksforGeeks:os.walk() in Python
- Stack Overflow:A Faster way of Directory walking instead of os.listdir?,这个问题是讨论os.walk等的运行效率的
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
的同时就要写好筛选文件的正则表达式,如上。
参考:
- python官方文档:glob — Unix style pathname pattern expansion
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是一个目录(反之也可以),则会分别抛出一个
IsADirectoryError
或NotADirectoryError
错误。 - 如果两个都是目录,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可以在重命名的时候捎带就移动个位置
参考:
- Stack Overflow:Rename and move file with Python
- os.rename vs shutil.move
- python官方文档:shutil.move(src, dst, copy_function=copy2)
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. 复制文件夹
- Copy file or directories recursively in Python
- 注意,copytree如果目标文件已经存在,会报错