以下代码演示了将 file://URL 转换为操作系统路径时出现的问题。
import os
import pathlib
import sys
import urllib.parse
print ("sys.argv[0] = {0}".format(sys.argv[0]))
varFilename = sys.argv[0]
varFilename = os.path.abspath(varFilename)
print ("abs varFilename = {0}".format(varFilename))
varMainFolder = os.path.dirname(varFilename)
print ("varMainFolder = {0}".format(varMainFolder))
varTarget = os.path.join(varMainFolder,"test test.py")
print ("varTarget = {0}".format(varTarget))
varURL = pathlib.Path(varTarget).as_uri()
print ("varURL = {0}".format(varURL))
varPathRaw = urllib.parse.urlparse(varURL).path
print ("varPathRaw = {0}".format(varPathRaw))
varPathDecode = urllib.parse.unquote(varPathRaw)
print ("varPathDecode = {0}".format(varPathDecode))
varOSPath = os.path.normpath(varPathDecode)
print ("varOSPath = {0}".format(varOSPath))
在 Linux 中,这段代码打印:
sys.argv[0] = test.py
abs varFilename = /home/ldbader/test.py
varMainFolder = /home/ldbader
varTarget = /home/ldbader/test test.py
varURL = file:///home/ldbader/test%20test.py
varPathRaw = /home/ldbader/test%20test.py
varPathDecode = /home/ldbader/test test.py
varOSPath = /home/ldbader/test test.py
注意 varOSPath 是一个完全有效的绝对路径。但在 Windows 中,代码打印:
sys.argv[0] = test.py
abs varFilename = C:\mli\Junk\test.py
varMainFolder = C:\mli\Junk
varTarget = C:\mli\Junk\test test.py
varURL = file:///C:/mli/Junk/test%20test.py
varPathRaw = /C:/mli/Junk/test%20test.py
varPathDecode = /C:/mli/Junk/test test.py
varOSPath = \C:\mli\Junk\test test.py
注意 varOSPath 有一个绝对路径,前面有一个无效的反斜杠。尝试使用此路径打开文件将失败。我原以为 os.path.normpath() 会丢弃驱动器规范左侧的斜线,但事实并非如此。
我应该怎么做才能使相同的逻辑在两个平台上为我提供有效的绝对路径?
最佳答案
好吧,这就是我的答案。它似乎适用于我的场景,但我不确定如果 Linux 用户创建名为/C:(或任何其他看起来像 Windows 驱动器盘符的名称)的文件夹会发生什么。
import os
import pathlib
import sys
import urllib.parse
print ("sys.argv[0] = {0}".format(sys.argv[0]))
varFilename = sys.argv[0]
varFilename = os.path.abspath(varFilename)
print ("abs varFilename = {0}".format(varFilename))
varMainFolder = os.path.dirname(varFilename)
print ("varMainFolder = {0}".format(varMainFolder))
varTarget = os.path.join(varMainFolder,"test test.py")
print ("varTarget = {0}".format(varTarget))
varURL = pathlib.Path(varTarget).as_uri()
print ("varURL = {0}".format(varURL))
varPathRaw = urllib.parse.urlparse(varURL).path
print ("varPathRaw = {0}".format(varPathRaw))
varPathDecode = urllib.parse.unquote(varPathRaw)
print ("varPathDecode = {0}".format(varPathDecode))
varOSPath = os.path.normpath(varPathDecode)
print ("varOSPath = {0}".format(varOSPath))
varFixedPath = varOSPath
varDrive = os.path.splitdrive(varFixedPath[1:])[0]
print ("varDrive = {0}".format(varDrive))
if varDrive:
varFixedPath = varFixedPath[1:]
print ("varFixedPath = {0}".format(varFixedPath))
技巧是在删除第一个字符后在绝对路径上使用 os.path.splitdrive()。对于 Windows 绝对路径,它将返回驱动器规范。对于 Linux 绝对路径,它将返回一个空字符串。如果驱动器规范是空字符串,则按原样使用绝对路径。如果驱动器规范不是空字符串,则从绝对路径中删除第一个字符并使用结果。
我仍然认为 os.path.normpath() 方法不应返回带有前导反斜杠的绝对 Windows 路径。
关于python - 在 Python 3 中,如何转换文件 ://URL to an OS path with code that works in both Linux and Windows?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43103640/