python标准库——os模块常用方法

本文最后更新于:12 小时前

写在前面:

Python的os模块是Python的标准库之一,是访问多种操作系统的接口,主要涉及与文件系统的交互和操作功能 ,具有如下作用:

  • 路径操作(os.path模块)

  • 文件和目录操作、文件属性获取

  • 执行系统命令、执行特定系统功能

  • 环境变量管理

  • 进程管理

鉴于网上对os相关方法的说明和使用大多太过含糊简单(特别是某菜鸟编程),或者存在错误理解和使用(特指某些博客),所以写了这篇文章,也是方便自己后续忘记时再次查看os模块中一些常用方法的特定用法

如果你能够读懂os模块的各个方法的源码,并且有耐心去读的话,那我建议跳过我的使用部分,可能看源码能够有更准确通透的理解。

观前提醒:需要读者起码具备基本的python代码阅读能力,对python中的字符串有基本的了解(特别是反斜杠""),能够理解什么是字符串的转义,什么是相对路径、绝对路径(不要拿着什么文件名就问为什么找不到这个文件),并且起码了解windows下的路径(Linux都懂的话看我的博客我觉得应该没什么障碍),有不懂的部分自行谷歌百度吧,总有比我讲的好的

更重要的一点:如果你是初学者,希望使用os模块完成简单的路径操作的工作的话,我建议直接学pathlib模块的方法,比os要好,os太繁琐了,只是很多开源项目都是用的os模块,一点不懂的话可能看不懂内容,这个怎么取舍看各位了

学习pathlib模块的话可以先看这篇知乎的文章入个门:

Python路径操作模块pathlib,看这篇就够了! - 知乎 (zhihu.com)

python路径操作新标准:pathlib 模块 - 知乎 (zhihu.com)

我的整理的话没有什么逻辑,基本是用了什么方法就整理了什么方法,后续也会不定期更新没有的方法(只要用上了就更)

0.os.path模块中使用的数据类型

如果是初学者,可以跳过下面的复杂说明,并默认os模块中的方法支持的数据类型为str类型和bytes类型,可以先不考虑自定义的路径类

os模块中的os.path模块对各个方法提供了相应的类型别名,指定了各个方法支持传入的数据类型,为了避免使用python的typing库一次次进行类型注解,或能够处理特定的数据类型,os模块使用了自定义的类PathLike和其他库中支持的类型别名Anystr、StrPath、BytesPath、StrOrBytesPath进行类型注解,以说明每个方法可以使用的数据类型

注意,windows下请查看stdlib库的ntpath.pyi文件以获得os.path模块对各方法的类型注解,Linux下则需要查看stdlib库的pkgutil.pyi文件,另外,有部分方法的类型注解存放在genericpath.pyi文件下,此部分是两个操作系统共用的

此处对使用的各个类型进行详细的说明:

  • PathLike :class PathLike(abc.ABC)

    是一个继承自抽象基类(abstract base class, ABC),用于实现文件系统路径协议,使用者可以通过继承PathLike类,实现该类的抽象方法来自定义自己的路径类

    PathLike类含有的方法包括:

    • __fspath__:(@abc.abstractmethod)返回对象的文件系统路径表示,可以是str或者bytes类型,即在自定义类实现该方法,使得类的实例对象能够对应一个指定的路径,然后可以使用open()方法或者os模块的方法将实例对象作为一个参数传入这些方法中进行相应的路径操作

      __fspath__是所有继承PathLike的子类必须实现的方法

    • __subclasshook__:(@classmethod)检查传入的类cls是否是PathLike的子类,通过其是否实现了 _fspath_ 方法作为判断标准,并返回判断结果,如果传入的类继承PathLike但未实现__fspath__ 方法,也认为该类并不是PathLike类的子类

    • _class_getitem_:用于支持PathLike的泛型语法

    其源代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class PathLike(abc.ABC):

    """Abstract base class for implementing the file system path protocol."""

    @abc.abstractmethod
    def __fspath__(self):
    """Return the file system path representation of the object."""
    # NotImplementedError继承自RuntimeError
    raise NotImplementedError

    @classmethod
    def __subclasshook__(cls, subclass):
    if cls is PathLike:
    # _check_methods是_collections_abc的一个内置方法,用于检查类是否有对应方法名
    return _check_methods(subclass, '__fspath__')
    # NotImplemented实际是None
    return NotImplemented

    # 支持泛型使用,可以用PathLike[str]形式,GenericAlias是实现参数化的类型
    __class_getitem__ = classmethod(GenericAlias)

    使用者可以据此定义自己的路径类并用于os模块和open()方法,下面是一个简单的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ##      自定义PathLike子类       ##
    class My_PathClass(os.PathLike):
    def __init__(self, path: str):
    """保存传入的路径"""
    self._path = path

    def __fspath__(self):
    """将保存的路径作为类的路径使用"""
    return self._path

    # 简单测试子类实例作为path方法中的参数使用
    mypathclass = My_PathClass("./os_test.py")
    print(os.path.abspath(mypathclass))
    # result : H:\py_ipynb\audio_to_text_and_translate\os_test.py

    # 测试读取内容,result略
    with open(mypathclass, encoding= 'utf-8') as f:
    print(f.read())
  • AnyStr :TypeVar('AnyStr', bytes, str)

    是typing模块中定义的一个泛型类型变量,名称为AnyStr,对应数据类型为str和bytes,为字符串和字节串的数据类型情况提供灵活和强大的类型注解支持

  • StrPath :Union[str, PathLike[str]]

    是一个联合类型别名,表示一个可以是字符串实现了PathLike接口的对象(PathLike对象需要返回str类型

    typing库的Union类型注解表示的是传入的参数可以是在"[]"内多种类型中的任何一种

  • BytesPath :Union[bytes, PathLike[bytes]]

    是一个联合类型别名,表示一个可以是字节串实现了PathLike接口的对象(PathLike对象需要返回bytes类型

  • StrOrBytesPath :Union[str, bytes, PathLike[str], PathLike[bytes]]

    是一个联合类型别名,表示一个可以是字符串字节串实现了PathLike接口的对象(PathLike对象需要返回str类型或bytes类型

1.os.path模块:

(1)os.path.join方法:

用途:拼接多个路径并返回最后的拼接结果

方法原型:os.path.join(path1[, path2[, ...]])

参数说明:

  • path1:需要拼接的第一个路径片段,StrPath类型或BytesPath类型,该参数必须传递

  • path2:需要拼接的第二个路径片段,StrPath类型或BytesPath类型,该参数可选

  • …:其他需要拼接的路径片段,StrPath类型或BytesPath类型,均可选

    需要注意的是,所有的路径片段的数据类型必须相同,即不可以将StrPath类型与BytesPath类型混用

返回值:合并后的路径, 如果路径片段是StrPath,返回类型为str,如果是BytesPath,返回类型为bytes

使用:

最简单的拼接是拼接目录+文件名,该方法会自动识别操作系统并补全目录分隔符,可以输入多级目录一次性合并

1
2
3
4
print(os.path.join("D:\\video", "test.m4a"))    # result: D:\video\test.m4a
print(os.path.join("E:", "video", "audio\\test", "test.m4a")) # result: E:video\audio\test\test.m4a
print(os.path.join("video", "test.m4a")) # result: video\test.m4a
print(os.path.join("/video", "test.m4a")) # result: /test.m4a

该方法实际有很多需要考虑的问题:

首先要注意的是,os.path.join方法全程不会去考虑路径是否真实存在,是否是有效路径,它只是一个处理字符串格式的路径方法,不涉及任何目录和文件的读写

其次要注意的是,如果输入的路径有绝对路径(此处指以"/"开头的路径或者以盘符开头的路径),os.path.join会根据情况对其中的部分参数的路径进行丢弃,规则如下:

  • 在不包括任何盘符时:

    • 只有一个绝对路径:绝对路径之前的全部参数会被全部丢弃
    • 存在多个绝对路径:最后一个绝对路径之前的全部参数会被全部丢弃
  • 存在单个或多个盘符时:

    绝对路径的逻辑同不包括任何盘符时的情况,但是丢弃参数时会保留最后一个出现的盘符,即,单独判断盘符出现的位置,选择最后一个盘符保存到路径中(即使这个盘符对应的后续路径被丢弃)

从这些规则中可以看出,存在绝对路径时的逻辑是,只保留最后一个出现的盘符和绝对路径

1
2
3
4
5
6
7
8
9
10
11
# result: /audio\test.m4a ——绝对路径"/audio"前面的"root_path"和"video"被丢弃
print(os.path.join("root_path", "video", "/audio", "test.m4a"))

# result: /test\test.m4a ——最后一个绝对路径"/test"之前的root_path"、"/video"和"/audio"被丢弃
print(os.path.join("root_path", "/video", "/audio", "/test", "test.m4a"))

# result: E:/audio\test.m4a ——最后一个绝对路径/audio"之前的参数""test"、"/action"和"/audio"被丢弃.而"E:\\video"的"\\video"被丢弃,"E:"盘符被保留
print(os.path.join("E:\\video", "test", "/action", "/audio", "test.m4a"))

# result: E:/video\test.m4a ——最后一个绝对路径/video"之前的参数"\\action"、"F:/test"和"E:\\audio"除最后一个盘符"E:"外均被丢弃
print(os.path.join("\\action", "F:/test", "E:\\audio", "/video", "test.m4a"))

另外,对于出现在最后一个绝对路径之后的相对路径,会被原样保存:

1
2
# result: F:/video\./audio\test.m4a ——出现在最后一个绝对路径/video之后的相对路径./audio会被原样保存
os.path.join("F:/test", "/video", "./audio", "test.m4a")

而对于只有相对路径的情况,os.path.join会正常保存,不对相对路径做任何处理,所以需要绝对路径时需要使用os.path.abspath方法获得绝对路径再拼接,尽量不要在拼接后再使用os.path.abspath方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
# result: H:\py_ipynb\audio_to_text\save_video\test.m4a 路径正确
print(os.path.abspath(os.path.join("./save_video", "test.m4a")))

# result: H:\py_ipynb\audio_to_text\save_video\test.m4a 路径正确
print(os.path.join(os.path.abspath("./save_video"), "test.m4a"))

# result: H:\py_ipynb\audio_to_text\audio\save_video\test.m4a
# 路径错误,因为相对路径的格式有问题,此处os.path.abspath只是拼接了当前工作路径和传入的路径,并将"."去除完成拼接
# 此处是audio\./save_video\test.m4a
print(os.path.abspath(os.path.join("audio", "./save_video", "test.m4a")))

# result: H:\py_ipynb\audio_to_text\save_video\test.m4a #路径正确
print(os.path.join("/audio", os.path.abspath("./save_video"), "test.m4a"))

可以看到,在某些情况下,先拼接相对路径再转绝对路径会出现问题,推荐拼接时先将相对路径转为绝对路径

最后,如果传入的最后一个路径是空字符串,则该方法会为路径最后添加一个目录分隔符作为结尾:

1
2
# result: ./save_video\
print(os.path.join("./save_video", ""))

(2)os.path.abspath方法:

用途:获得指定文件/目录路径的绝对路径

方法原型:os.path.abspath(path)

参数说明:path:需要获得绝对路径的对应文件的路径,AnyStr或者PathLike[AnyStr]类型,可以是绝对路径/相对路径

返回值:AnyStr类型,返回其对应的绝对路径

使用:

os.path.abspath方法没有想象的那么简单,其实际的使用基于os.getcwd方法,其内部逻辑分为三步:

  1. 检验path是否是绝对路径,如果是,则直接返回

  2. 否则,利用os.getcwd方法(如果path是Unicode编码,使用os.getcwdu方法)获得当前的工作路径

  3. 将传入的path与当前工作路径进行路径拼接

在传入的path为绝对路径或者基于当前工作路径的正确相对路径时,该方法的工作是正常的,可以获得正确的绝对路径。但如果path是非当前工作目录的文件名,或者是错误的文件相对路径时,该方法只会错误的将传入的path与当前工作路径直接拼接,详细例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 在子目录下有一个vidio/test.m4a文件
print(os.path.abspath("./vidio/test.m4a"))

# 在其他目录下有一个music_translate\music_use.ipynb文件路径
# result :H:\py_ipynb\music_trans\music_use.ipynb 结果准确
print(os.path.abspath("../music_translate/music_use.ipynb"))

# 传入错误的test.m4a文件相对路径
# result: H:\py_ipynb\audio_to_text\error_vidio\test.m4a 结果错误,只是去掉了"."后进行了拼接
print(os.path.abspath("./error_vidio/test.m4a"))

# 直接传入music_use.ipynb文件路径
# result: H:\py_ipynb\audio_to_text\music_use.ipynb 结果错误,只是进行了拼接
print(os.path.abspath("music_use.ipynb"))

# 传入错误的music_use.ipynb文件相对路径
# result: H:\py_ipynb\error\music_use.ipynb 结果错误,只是去掉了".."和当前工作路径的最后一个目录后进行了拼接
print(os.path.abspath("../error/music_use.ipynb"))

# 随便传入一个字符串
# result: H:\py_ipynb\audio_to_text\you are happy 结果错误,只是进行了拼接
print(os.path.abspath("you are happy"))

由此可以看出,该方法实际并不判断文件是否存在,路径是否有效,其只是将当前工作路径和传入的字符串中有效的相对路径进行合并,然后直接拼接,所以需要谨慎使用,或者结合其他判断路径/文件存在方法使用

另外,如果传入的是一个以"/"开头的绝对路径,该方法会直接将盘符与传入路径字符串进行合并:

1
2
3
# 传入一个绝对路径
# result: H:\test.m4a 仅将盘符与其拼接
os.path.abspath("/test.m4a")

(2)[续]os.path.realpath方法:

用途:获得指定文件/目录路径的绝对路径

方法原型:os.path.realpath(path, strict= False)(Python3.10以上版本有额外参数strict,3.9及以下是没有的)

参数说明:

  • path:需要获得绝对路径的对应文件的路径,AnyStr或者PathLike[AnyStr]类型,可以是绝对路径/相对路径

  • strict:解析符号链接的模式(详见下方使用部分),True时表示严格模式,如果路径中的任何部分(包括符号链接的目标路径)不存在,会抛出错误FileNotFoundError,即使用的必须是文件系统实际存在的路径False时表示非严格模式,此时方法会尽可能地解析路径的符号链接,但路径中某些部分不存在时不会引发错误,即允许路径包含未创建的部分

    对于Python3.9及以下版本使用效果和strict= False相同

返回值:AnyStr类型,返回解析结果对应的绝对路径

使用:

os.path.realpath方法与os.path.abspath方法的基本用法是一致的,但前者在将相对路径转换为绝对路径时,会解析路径中的符号链接(软链接),返回实际文件/目录的绝对路径

对于Windows用户,此处的软链接并非快捷方式,创建软链接需要使用cmd的mklink命令(详见这个博客Windows:在Windows下创建并删除软连接_如何查询windows删除软链接-CSDN博客)

下面仅说明和os.path.abspath方法不同的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# # 3.10以后可用,对不存在的文件strict为False时不报错
# # result:H:\py_ipynb\audio_to_text_and_translate\you are happy
# print(os.path.realpath("you are happy", strict=False))

# # 3.10以后可用,对不存在的文件strict为True时报错FileNotFoundError
# print(os.path.realpath("you are happy", strict=True))

# 否则这样使用,和strict=False的效果相同
# result: H:\py_ipynb\audio_to_text_and_translate\you are happy
print(os.path.realpath("you are happy"))

# 尝试解析符号链接,链接为当前文件
# H:\py_ipynb\audio_to_text_and_translate\os_test.py,此为软链接指向的文件
print(os.path.realpath("./video/link.py"))

(2)[续]os.path.isabs方法:

用途:判断指定文件/目录路径是否为绝对路径

方法原型:os.path.isabs(path)

参数说明:path:指定的路径字符串,StrOrBytesPath类型,可以是绝对路径/相对路径

返回值:bool类型,True表示路径是绝对路径,False表示不是绝对路径

使用:

os.path.isabs方法只是判断path是否是一个绝对路径,即该参数值是否符合绝对路径的格式,不会判断该绝对路径是否是真实存在的

1
2
3
4
5
6
7
8
9
10
11
12
13
##       os.path.isabs方法:判断传入路径是否是绝对路径       ##
# 相对报错
print(os.path.isabs("./music_use.ipynb")) # False
# 任意字符串报错
print(os.path.isabs("you are happy")) # False
# 绝对无论是否存在均不报错
print(os.path.isabs("H:\py_ipynb\\audio_to_text_and_translate\os_test.py")) # True
print(os.path.isabs("H:\py_ipynb\error\music_use.ipynb")) # True
# 注意格式需要正确,以及转移字符不一定影响正确性
print(os.path.isabs("K:\\root\c\c\c\d")) # True
print(os.path.isabs("K:\\root\ac\c\c\d")) # True
print(os.path.isabs("K:\root\c\c\c\d")) # False
print(os.path.isabs("Kk:\\root\c\c\c\d")) # False

(3)os.path.splitext方法:

用途:将传入路径分割,获得文件路径名称(无扩展名)和文件扩展名

方法原型:os.path.splitext(path)

参数说明:path:分割的路径,AnyStr或者PathLike[AnyStr]类型,一般是绝对路径(相对路径也可以,但该方法不会主动转化相对路径为绝对路径)

返回值:含两个AnyStr元素的元组,前者为文件路径名称(包括文件所在目录路径+文件名称),后者为文件扩展名

使用:

os.path.splitext方法实际是通过从右向左寻找第一个点号分隔符完成的分割操作,如果没有点号分隔符(目录/无后缀文件),则第二个元素(扩展名部分)为空字符串

该方法可用于更换扩展名、计算某文件夹下的对应文件类型数量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 通过分割将txt扩展名更换为md
file_use = "D:/save/a.txt"
# result:('D:/save/a', '.txt')
print(os.path.splitext(file_use))
new_suffix = ".md"
# result: D:/save/a.md
print(os.path.splitext(file_use)[0] + new_suffix)

# 统计对特定目录的txt文件数量
target_dir = "D:/file_count"
file_number = 0
for root, dirs, files in os.walk(target_dir):
for file in files:
if os.path.splitext(file)[1] == ".txt":
file_number += 1
# result: file_number = 10
print(file_number)

# 无扩展名文件的第二个元素是空字符串
file = "D:/save/a"
# result: ""
print(os.path.splitext(file)[1])

(3)[续]os.path.split方法:

用途:将传入路径分割,获得文件目录路径文件名(文件名称+扩展名)

方法原型:os.path.split(path)

参数说明:path:分割的路径,AnyStr或者PathLike[AnyStr]类型,一般是绝对路径(相对路径也可以,但该方法不会主动转化相对路径为绝对路径)

返回值:含两个AnyStr元素的元组,前者为文件目录路径,后者为文件名

使用:

os.path.split方法实际是通过从右向左寻找第一个路径分隔符完成的分割操作,如果没有路径分隔符,则第一个元素(目录路径部分)为空字符串

如果路径以路径分隔符结尾,第二个元素(文件名部分)为空字符串

该方法可用于文件重命名(基于已有名称),路径规范化,通常与os.path.joinos.path.normpath组合使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 通过分割将文件名中的序号+1并规范化文件名
file_use = "D:/save/1.txt"
# result:('D:/save/', '1.txt')
file_split = os.path.split(file_use)
print(file_split)
new_filename = str(int(file_split[1][0]) + 1) + file_split[1][1:]
# result: D:/save/2.txt
print(os.path.normpath(os.path.join(file_split[0], new_filename)))

# 没有路径分隔符的第1个元素是空字符串
file_use = "D:/save"
# result: ('D:/', 'save')
print(os.path.split(file_use))

# 以路径分隔符结尾的第2个元素是空字符串
file_use = "D:/save/"
# result: ('D:/save', '')
print(os.path.split(file_use))

(3)[续]os.path.dirname方法:

用途:获得指定路径的文件目录路径部分

方法原型:os.path.dirname(path)

参数说明:path:指定的文件路径,AnyStr或者PathLike[AnyStr]类型,一般是绝对路径(相对路径也可以,但该方法不会主动转化相对路径为绝对路径)

返回值:AnyStr类型,返回指定路径的目录路径部分

使用:

实际获得的是os.path.split方法所分割的第一个元素

1
2
3
4
file_use = "D:/save/1.txt"
# result:D:/save/
dir_name = os.path.dirname(file_use)
print(dir_name)

(3)[续]os.path.basename方法:

用途:获得指定路径的文件名部分

方法原型:os.path.basename(path)

参数说明:path:指定的文件路径,AnyStr或者PathLike[AnyStr]类型,绝对路径/相对路径均可

返回值:AnyStr类型,返回指定路径的文件名部分

使用:

实际获得的是os.path.split方法所分割的第二个元素

1
2
3
4
file_use = "D:/save/1.txt"
# result:1.txt
base_name = os.path.basename(file_use)
print(base_name)

(4)os.path.exists方法:

用途:判断文件系统中是否存在与传入的路径所对应的真实文件/目录

方法原型:os.path.exists(path)

参数说明:path:传入的路径,StrOrBytesPath类型,可以是绝对路径/相对路径

返回值:bool类型,True表示传入路径存在真实文件/目录,False表示不存在真实文件/目录

使用:

该方法较简单,但是要注意传入路径的转义,在path前加"r"完成转义,另外,注意同一路径可能有同名的目录和文件,注意区别:

1
2
3
4
5
6
7
file_use = r"D:\save\1.txt"
print(os.path.exists(file_use)) # True
file_use = r"D:\save\2.txt"
print(os.path.exists(file_use)) # False
print(os.path.exists("./os_test.py")) # True
print(os.path.exists("./video")) # True
print(os.path.exists("./no_exist")) # False

(4)[续]os.path.isdir方法:

用途:判断文件系统中是否存在与传入的路径所对应的真实目录

方法原型:os.path.isdir(path)

参数说明:path:传入的路径,StrOrBytesPath类型,可以是绝对路径/相对路径

返回值:bool类型,True表示传入路径存在真实目录,False表示不存在真实目录

使用:

该方法逻辑和os.path.exists基本相同,判断的目标从是否存在文件/目录变为了是否是目录,使用该方法需要注意目录和文件存在同名现象,需要判断使用场景:

1
2
3
4
5
file_use = r"D:\save\1.txt"
print(os.path.isdir(file_use)) # False
# 文件夹以"."+特定后缀名结尾判断
file_use = r"D:\save\dir.txt"
print(os.path.isdir(file_use)) # True

(4)[续]os.path.isfile方法:

用途:判断文件系统中是否存在与传入的路径所对应的真实文件

方法原型:os.path.isfile(path)

参数说明:path:传入的路径,StrOrBytesPath类型,可以是绝对路径/相对路径

返回值:bool类型,True表示传入路径存在真实文件,False表示不存在真实文件

使用:

该方法逻辑和os.path.exists基本相同,判断的目标从是否存在文件/目录变为了是否是文件,使用该方法需要注意目录和文件存在同名现象,需要判断使用场景:

1
2
3
4
5
file_use = r"D:\save\1.txt"
print(os.path.isfile(file_use)) # True
# 文件夹以"."+特定后缀名结尾判断
file_use = r"D:\save\dir.txt"
print(os.path.isfile(file_use)) # False

(5)os.path.normpath方法:

用途:规范化路径字符串

方法原型:os.path.normpath(path)

参数说明:path:传入的路径,AnyStr或者PathLike[AnyStr]类型,可以是绝对路径/相对路径

返回值:AnyStr类型,返回规范化后的路径字符串

使用:

os.path.normpath方法是一个仅操作路径字符串的方法,不会访问文件系统具有操作系统依赖性

该方法的规范化方法主要包括:

  • 去除冗余的分隔符:将连续的分隔符合并为一个

  • 移除当前目录引用:当前目录引用 . 会被移除,因为其不改变路径

  • 解析上层目录引用:上层目录引用 .. 会被解析为返回上一级目录,即移除上层目录引用的前一个目录路径

  • 转换路径分隔符:自动将路径的分隔符转换为当前操作系统的默认分隔符

实际效果如下(windows平台):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 规范绝对路径
# result: D:\save\1.txt
print(os.path.normpath("D://////save\\\\1.txt"))

# 规范相对路径
# result: os_test.py
print(os.path.normpath("./\/\/\/\os_test.py"))
# result: ..\dir_file.txt
print(os.path.normpath(".///..///dir_file.txt"))

# 规范有冗余的相对路径
# result: folder\file.txt
# 移除多余的"/" -> ./folder/./subfolder/../file.txt
# 转换路径分隔符 -> .\folder\.\subfolder\..\file.txt
# 移除"." -> folder\subfolder\..\file.txt
# 解析"..",将\subfolder\..移除 -> folder\file.txt
print(os.path.normpath("./folder///./subfolder//../file.txt"))

# result: ..\dir_file.txt
print(os.path.normpath("../\/\././/./dirname/../dir_file.txt"))

2.os.getcwd方法:

用途:获得当前工作目录(working directory)的路径

方法原型:os.getcwd()

参数说明:无

返回值:当前的工作目录路径,在Python3中返回类型为unicode字符串(str数据类型),在Python2中返回类型为字节字符串(bytes数据类型)

使用:

os.getcwd()返回的不是使用该方法的py脚本文件的目录的路径,而是是运行/调用/执行脚本的工作文件的目录的路径前者称为当前文件目录,后者称为当前工作路径,如果希望获得当前文件路径的话,需要使用**_file_**属性,而目录需要结合其他os模块方法获得

如果执行脚本即为运行**os.getcwd()_file_**的脚本,则当前工作目录和当前文件目录是一致的

一般情况下,**os.getcwd()_file_**会结合os.path.abspathos.path.dirname使用:

  • 当前文件路径通过os.path.abspath(_file_))获得(直接__file__也可以)

  • 当前文件目录通过os.path.abspath(os.path.dirname(_file_))获得

  • 当前工作目录通过os.path.abspath(os.getcwd())获得(直接os.getcwd()也可以)

1
2
3
4
5
6
7
8
9
10
11
12
##      os.getcwd方法:获得当前工作路径        ##
# 当前工作目录
# result: H:\py_ipynb\audio_to_text_and_translate
print(os.path.abspath(os.getcwd()))

# 当前文件路径
# result: H:\py_ipynb\audio_to_text_and_translate\os_test.py
print(os.path.abspath(__file__))

# 当前文件目录
# result: H:\py_ipynb\audio_to_text_and_translate
print(os.path.abspath(os.path.dirname(__file__)))

2.[续]os.getcwdu方法(Python3已移除):

只能在Python2中使用,且返回类型为unicode字符串(str数据类型),其返回内容和Python3中os.getcwd()方法相同

Python3用户请不要使用此方法

2.[续]os.getcwdb方法(仅限Python3):

只能在Python3中使用,且返回类型在Python3.8之前为ANSI编码的字节字符串(bytes数据类型),在Python3.8及以后为UTF-8的编码的字节字符串(Python 3.8 有什么新变化 — Python 3.8.19 文档),其返回内容和Python3中os.getcwd()方法相同

Python2用户请不要使用此方法

3.os.walk方法:

用途:递归地遍历指定目录下的全部子文件及子目录的全部文件

方法原型:os.walk( top [, topdown=True [, onerror=None [, followlinks=False] ] ] )

参数说明:

  • top:需要遍历的目录,AnyStr或者PathLike[AnyStr]类型,该参数必须传递

  • topdown:是否优先遍历top对应的目录,bool类型,True时优先遍历top目录,对应目录树的向下查找;False时优先遍历top子目录,对应目录树的向上查找,默认为True,该参数可选

  • onerror:自定义的回调函数,Callable对象类型(实际是Callable[[OSError], Any]),在os.walk遇到异常(权限不足、文件被删除或无法访问)时调用onerror处理遍历时发生的错误,可以使用日志记录,输出错误信息等函数作为onerror参数,默认为None,该参数可选

  • followlinks:是否遍历目录下的快捷方式实际指向的目录 ,bool类型,True时遍历快捷方式实际指向的目录,False时不遍历快捷方式实际指向的目录,默认为False,该参数可选

返回值:os.walk返回一个生成器对象,类型为Iterator[tuple[AnyStr, list[AnyStr], list[AnyStr]]],实际上,其每次返回的是(root,dirs,files)的三元组作为该次遍历时的返回值

  • rootAnyStr类型,对应当前遍历的目录路径

  • dirs:**list[AnyStr]**类型,对应当前遍历的目录下的全部目录名集合

  • files:**list[AnyStr]**类型,对应当前遍历的目录下的全部文件名集合

使用:如果希望获得的是top目录下的文件/目录的相对路径,需要将root与dirs/files拼接,此处可使用os.path.join方法完成,例子如下:

1
2
3
4
5
path_files = []
for root, dirs, files in os.walk(path):
for file in files:
path_files.append(os.path.join(root, file))
return path_files

如果希望该路径是绝对路径,需要在append方法前使用os.path.abspath方法:

1
2
3
4
5
path_files = []
for root, dirs, files in os.walk(path):
for file in files:
path_files.append(os.path.abspath(os.path.join(root, file)))
return path_files

4.os.makedirs方法:

用途:递归地创建多级目录,对于中间级不存在的目录也会自动创建

方法原型:os.makedirs(name [, mode=0o777 [, exist_ok=False]])

参数说明:

  • name:需要递归创建的目录路径,StrOrBytesPath类型,可以是绝对路径/相对路径,该参数必须传递

  • mode:Linux目录权限数字模式,windows下该参数无效,int类型(一般用3位八进制数字表示),默认为0o777(即任何用户均可读可写可执行),该参数可选

  • exist_ok:是否在目录存在时抛出异常,bool类型,如果name已存在且为目录,在exist_ok为True不抛出异常,否则均抛出FileExistsError异常(Windows下为WinError183),默认为False,该参数可选

返回值:无返回值

使用:该方法实际上要注意的点很多

首先,在基本使用时,由于其递归创建多级目录,所以在中间级目录名出现错误的情况下该方法不会报错,而是会沿着一个错误的路径进行创建,需要注意检查:

1
2
3
# 尝试当前目录创建
os.makedirs(name="./test") # 正确,在当前工作目录子目录下创建了一个test目录
os.makedirs(name="./vidio/test") # 错误,创建了不存在的vidio目录,并在该目录下创建了test目录,与实际预期不符

其次,Linux用户需要考虑mode模式的权限,有些目录的权限不可使用默认的777;而windows用户无论怎么修改mode,实际对创建的目录是没有权限影响的,使用的都是windows默认创建目录的权限,需要自行手动修改:

image-20240415132343397

上图为手动创建的video文件夹和指定mode=0o111时创建的vidio文件夹,可以看到二者权限完全一致(其他组/用户也相同,此处不再一一展示)

另外,使用os.path.exists方法和该方法的一种常见创建多级目录方法:

1
2
3
# 错误的创建方法
if not os.path.exists(path):
os.makedirs(path)

这样的处理是错误的,在多线程或多进程环境中,即使在执行两个方法之间没有其他线程或进程修改文件系统,也同样存在着竞态条件:

假定存在线程A、B,线程A执行了os.path.exists方法后被操作系统中断——此时操作系统切换到线程B,因为path未存在,线程B执行了完整的os.path.existos.makedirs方法并创建了path目录——线程B被操作系统中断并切换到线程A,此时的A在执行os.makedirs方法时就会因path目录已存在而抛出异常,影响程序执行

解决的方法是设置exist_ok为True避免报错,且此目录一旦被创建,其他线程/进程希望创建此目录时能够发现此目录已存在,进而终止创建操作,保证创建时不会报错

同时,考虑到目录和文件可能同名影响创建,判断时最好使用os.path.isdir方法判断name是否是一个目录:

1
2
3
# 正确的创建方法
if not os.path.isdir(path):
os.makedirs(path, exist_ok = True)

4[续].os.mkdir方法:

用途:创建单级目录,即对于多级目录的路径,只为最后一级目录创建

方法原型:os.makedirs(path [, mode=0o777])

参数说明:

  • path:需要创建的目录路径,StrOrBytesPath类型,可以是绝对路径/相对路径,该参数必须传递

  • mode:和os.makedirs方法的mode相同

返回值:无返回值

使用:

该方法的使用较简单,其创建只针对最后一级目录,如果最后一集目录的上级目录有任何一级不存在均会抛出FileNotFoundError错误(Windows下为WinError3),如果已存在文件/目录与path对应,则抛出FileExistsError异常,否则正常创建目录,故一般先使用os.path.isdir方法判断path是否是一个目录:

1
2
if not os.path.isdir(path):
os.mkdir(path)

python标准库——os模块常用方法
https://github.com/xiaohei07/xiaohei07.github.io/2024/07/14/python标准库——os模块常用方法/
作者
07xiaohei
发布于
2024年7月14日
许可协议