首页 > 解决方案 > 为什么从 os.walk() 返回的 root 包含 / 作为目录分隔符而 os.sep(或 os.path.sep)在 Win10 上返回 \?

问题描述

为什么从os.walk()返回的根元素显示 / 作为目录分隔符但os.sep(或os.path.sep)在 Win10 上显示 \?

我只是想为文件夹中的一组文件创建完整路径,如下所示:

import os

base_folder = "c:/data/MA Maps"
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))

print(os.path.sep)

这是我得到的输出:

c:/data/MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:/data/MA Maps\Map_of_Massachusetts_Norfolk_County.png
\

我知道 python 的一些库函数(如 open())将与混合路径分隔符一起使用(至少在 Windows 上),但依赖于该 hack 确实不能在所有库中得到信任。看起来从os.walk()os.path.sep.join())返回的项目应该根据所使用的操作系统产生一致的结果。谁能解释为什么会发生这种不一致?

PS - 我知道有一个更一致的库用于处理文件路径(以及许多其他文件操作) ,称为pathlib,它是在 python 3.4 中引入的,它似乎确实解决了所有这些问题。如果您的代码在 3.4 或更高版本中使用,是否最好使用pathlib方法来解决此问题?但是,如果您的代码是针对在 3.4 之前使用 python 的系统,那么解决这个问题的最佳方法是什么?

下面是pathlib的一个很好的基本解释:Python 3 Quick Tip: The easy way to deal with file paths on Windows, Mac and Linux

这是我使用pathlib的代码和结果:

import os
from pathlib import Path

# All of this should work properly for any OS. I'm running Win10.

# You can even mix up the separators used (i.e."c:\data/MA Maps") and pathlib still
# returns the consistent result given below.
base_folder = "c:/data/MA Maps" 

for root, dirs, files in os.walk(base_folder):
    # This changes the root path provided to one using the current operating systems
    # path separator (/ for Win10).
    root_folder = Path(root)
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
             # The / operator, when used with a pathlib object, just concatenates the
             # the path segments together using the current operating system path separator.
             print(root_folder / f)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

这甚至可以更简洁地使用pathlib和列表理解来完成(每个使用的操作系统都正确处理所有路径分隔符):

from pathlib import Path

base_folder = "c:/data/MA Maps"
path = Path(base_folder)
files = [item for item in path.iterdir() if item.is_file() and 
                                            str(item).endswith(".png") and 
                                            (str(item).find("_N") != -1)]
for file in files:
    print(file)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

这是非常 Pythonic 的,至少我觉得它很容易阅读和理解。.iterdir() 真的很强大,它使处理文件和目录相当容易,并且以跨平台的方式。你怎么看?

标签: pythonpython-3.xos.walkos.pathpath-separator

解决方案


该函数始终从您传递给它的内容os.walk中产生未更改的初始部分。dirpath它不会尝试对分隔符本身进行规范化,它只是保留您给它的内容。它确实对路径的其余部分使用系统标准分隔符,因为它将每个子目录的名称与根目录结合在一起os.path.join您可以在 CPython 源代码库中查看该os.walk函数的当前实现版本。

规范化输出中分隔符的一种选择是规范化传入的基本路径os.walk,可能使用pathlib. 如果您对初始路径进行规范化,则所有输出都应自动使用系统路径分隔符,因为它将是通过递归遍历保留的规范化路径,而不是非标准路径。这是您的第一个代码块的一个非常基本的转换,以规范化base_folderusing pathlib,同时保留所有其余代码,简单。它是否比使用更多pathlib功能的版本更好是我将留给您的判断电话。

import os
from pathlib import Path

base_folder = Path("c:/data/MA Maps")    # this will be normalized when converted to a string
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))

推荐阅读