提醒:本页面将不再更新、维护或者支持,文章、评论所叙述内容存在时效性,涉及技术细节或者软件使用方面不保证能够完全有效可操作,请谨慎参考!

Windows脚本宿主(Windows Scripting Host或WSH)确实给我们编写本地脚本带来了方便,但是如何获取脚本文件自身目录或者是任意文件所在的目录路径呢?在Win32编程中我们可以通过PathRemoveFileSpec这样的Path*系列API,来对文件路径进行处理,当然这里是脚本,正常情况下没有访问Win32 API的权限,不过也有变通的办法来实现类似的功能。

下面我以获取脚本所在文件夹目录路径为例,讲解一下如何处理这类问题,WSH为我们提供了一个环境变量,名称为WScript.ScriptFullName或者写成WSH.ScriptFullName,通过直接输出变量,我们很容易得到脚本的全路径,当然这个是包含脚本名称的,类似于C:\ScriptsFolder\Sample.vbs这样的路径,如何得到C:\ScriptsFolder\呢?比如我们要向这个目录下写入配置文件,大家肯定会想到,我们去掉Sample.vbs不就可以了,是的,这是个办法,当然去掉的办法有很多,比如说基本的InStrRev函数,查找\斜杠,然后再Left截取字符串,这个思路就形成了我们第一个函数PathRemoveFileSpec1:

Function PathRemoveFileSpec1(strFileName)
  ' 将类Unix路径 / 替换为 \
  strFileName = Replace(strFileName, "/", "\")
	
  Dim iPos
  ' 从路径末尾开始搜索\,这样从第一个字符到这个位置
  ' 就是我们所需要的
  iPos = InStrRev(strFileName, "\")
  ' 使用Left保留需要的部分
  PathRemoveFileSpec1 = Left(strFileName, iPos)
End Function

' 测试输出
WScript.Echo PathRemoveFileSpec1(WScript.ScriptFullName)

怎么样,是不是很容易就实现了?这里主要有个转换类Unix路径的步骤,用过类Unix系统的朋友知道,Windows下和类Unix下路径斜杠是不一样的,当然Windows下正常都是反斜杠\,这一步仅为保险起见。

谈到处理文本,很多朋友可能会想到正则表达式也称为正规表达式,这个可是它们的强项,是的,下面我们可以谈谈如何用正则表达式实现,正则表达式实现的一个好处就是类Unix的正斜杠和Windows的反斜杠都能兼顾到,可以不需要转换路径,当然InStrRev也可以多一步处理正斜杠,就是判断多了些,下面直接看正则实现的脚本吧:

Function PathRemoveFileSpec2(strFileName)
  Dim RegEx
  Set RegEx = New RegExp
    RegEx.Pattern = "([^\\/]*)$"
    ' 替换掉正斜杠/或者反斜杠\后面的内容
    PathRemoveFileSpec2 = RegEx.Replace(strFileName, "")
  Set RegEx = Nothing
End Function

' 测试输出
WScript.Echo PathRemoveFileSpec2(WScript.ScriptFullName)

好,这样也实现了,以上这两个函数都是基于文本处理的,其实VBS还可以操作强大的ActiveX COM组件,那么有没有直接类似的方法可以供我们调用呢?谈到文件处理,大家肯定会想到Scripting.FileSystemObject,对,就是它。其中有个方法就是GetParentFolderName,可以让我们获取指定文件所在的目录,脚本代码如下:

Function PathRemoveFileSpec3(strFileName)
  Dim fso,file
  Set fso = WSH.CreateObject("Scripting.FileSystemObject")
    Set file = fso.GetFile(strFileName)
	PathRemoveFileSpec3 = fso.GetParentFolderName(file)
	Set file = Nothing
  Set fso = Nothing
End Function

' 测试输出
WScript.Echo PathRemoveFileSpec3(WScript.ScriptFullName)

怎么样,很强大的方法吧?到这里基本上算是介绍完了,如果你单单只需要获取脚本所在文件夹基本上上面的任一函数也够用了,下面主要谈获取任意文件所在文件夹目录的问题,什么?上面的函数不可以吗?可以是可以,但是会有这样一种情况如果我用上面的函数处理已经是文件夹的路径比如C:\Windows,PathRemoveFileSpec1和PathRemoveFileSpec2返回C:\,PathRemoveFileSpec3直接报错,说是“文件未找到”,其实如果已经是文件夹,那么函数完全可以不用处理直接返回,除非你始终希望获取父路径,那么增强版的PathRemoveFileSpec4就诞生了:

Function PathRemoveFileSpec4(strFileName)
  Dim fso,file
  Set fso = WSH.CreateObject("Scripting.FileSystemObject")
    If fso.FileExists(strFileName) Then
      Set file = fso.GetFile(strFileName)
      PathRemoveFileSpec4 = fso.GetParentFolderName(file)
      Set file = Nothing
    ElseIf fso.FolderExists(strFileName) Then
      ' 如果已经是文件夹则不需要处理直接返回
      PathRemoveFileSpec4 = strFileName
    Else
      ' Oops 文件或文件夹不存在
      ' 原样返回当然也可以调用
      ' PathRemoveFileSpec2正则文本处理一下
      PathRemoveFileSpec4 = strFileName
    End If
  Set fso = Nothing
End Function

' 测试输出
WScript.Echo PathRemoveFileSpec4("C:\Windows")

这里我放弃了改造PathRemoveFileSpec1和PathRemoveFileSpec2,因为它们只能傻傻的去处理文本而不能判断是否已经是文件夹,好了,讲解基本上结束了,函数可能还不是很完美,欢迎大家补充,下面谈一下细节问题:文件夹末尾的反斜杠,通过以上函数处理过的路径有可能末尾已经带有反斜杠\,有可能没有,那么有没有类似于Win32 API的PathAddBackslash函数呢?当然没有了,还是需要我们自己动手,下面分享一下我写的PathAddBackslash:

Function PathAddBackslash(strFileName)
  Dim fso,file

  PathAddBackslash = strFileName
  Set fso = WSH.CreateObject("Scripting.FileSystemObject")
    If fso.FolderExists(strFileName) Then
	  Dim last
	  ' 文件夹存在
	  ' 截取最后一个字符
	  last = Right(strFileName, 1)
	  If last<>"\" And last<>"/" Then
		PathAddBackslash = strFileName & "\"
	  End If
	End If
  Set fso = Nothing
End Function

' 测试输出
WScript.Echo PathAddBackslash("C:\Windows")

PathAddBackslash的前提是strFileName必须是文件夹,否则按原样返回。

好了,讲解到此结束!如果你有更好的实现、想法或者问题欢迎交流:-)