VBA专题12:详解GetAttr函数
excelperfect
有时候,你可能会发现了解正在与之交互的文件或文件路径的基本文件属性很有用。如果你读取文件内容后再将内容写回文件,那么知道原始文件是否为只读是重要的,在这种情况下,你的写入将失败,或者如果它是系统文件,在这种情况下写入也可能会失败,但是如果成功,可能会损坏系统。有时候,你可能只想检查一个字符串是否确实指向一个有效的文件或目录。
VBA的GetAttr函数将返回文件的基本属性。注意,由于它是一个函数,因此输出一个值;它不是文件对象的属性,不能写入GetAttr来更改文件的属性。同样,也不能使用此函数将文件设为只读或隐藏文件。
可能的属性
有7种可能的属性,对于给定的文件路径,可能不止一个,但也有一些相互排斥的属性。
下表所示是属性列表,来自Microsoft文档。
表中的第一列是VBA中的名称,相对于第二列中的值更易理解。在VBA程序中,可以将 vbXX名称与数字值互换使用。
输出
GetAttr函数输出的究竟是什么呢?唯一的输出是一个等于所有真实属性总和的整数值。对于你的特定输入,无论哪个属性为真,都将出现在该函数的输出中。
最简单的情况是文件只满足一个属性。假设文件myFile是隐藏的,且是该文件唯一的一个属性,从上表中可知,语句GetAttr(myFile)将返回2。
更复杂一点的是隐藏的系统文件。此时,必须在总和中包含4和2,因此输出为6:GetAttr(myFile) =vbHidden + vbSystem = 6。
隐藏目录的值是多少?vbHidden+ vbDirectory = 2 + 16 = 18。一个隐藏的只读系统文件的值是多少?vbReadOnly+ vbHidden + vbSystem = 7。
数字是2的幂的原因是:每个属性组合将总是给出一个唯一的数字,并且二进制加法的机制使按位运算更容易。
这种巧妙的技术意味着多个属性可以由一个数字表示而不会丢失任何信息,就像多个维度合并为一个。
分离属性
你可以查看包含所有可能输出的表并了解存在哪些属性。然而,大多数时候我们只对一个属性感兴趣。只读输入的可能值是1、3、5、35等。但是,测试每一个都会很麻烦。为了使之更容易,我们可以依靠二进制按位运算的优点。
要查看特定属性是否存在,需要使用AND运算符并将结果值设置为整数:
iReadOnly = GetAttr(myFile) And vbReadOnly
如果输出为零,则vbReadOnly不是此文件的属性。如果输出不是零,则存在vbReadOnly。下面是使用VBA的If-Then语句测试只读属性的完整示例:
Sub VBA_GetAttr_Demo()
Dim myFile As String
Dim iReadOnly As Integer
myFile ='C:\Public\MySpreadsheet.xlsm'
iReadOnly= GetAttr(myFile) And vbReadOnly
If iReadOnly <> 0 Then
'文件是只读的
Else
'文件不是只读的
End If
End Sub
下面的第二个示例测试路径是目录还是文件:
Sub VBA_GetAttr_Demo_Dir()
Dim myPath As String
Dim iDirAs Integer
myPath ='C:\Public'
iDir =GetAttr(myPath) And vbDirectory
If iDir<> 0 Then
'选择了目录
Else
'没有目录
End If
End Sub
无论文件路径末尾是否有斜杠,这都将起作用。
测试就是这么简单。要使用GetAttr函数,不需要更多信息,但如果想了解如何分解返回的总和数值,看下面的讲解。
按位与分解
那么我们如何测试一个数字是否真的是和的一部分呢?可以通过使用按位与来实现。
计算中的每个数字都由一串位表示,可以是on/true或off/false,通常分别表示为1和0。我们可以对这些位进行两种运算:AND和OR,它们来自数学逻辑。对于本文,重点是AND运算,其两边都必须为true/on/1,才输出1。如果一侧或两侧为false/off/0,则输出为0。
当我们查看2的位串表示时,我们得到10,其前导零可以无限添加,因此10 =00000010 = 0010,重要的部分是末尾跟随的零(和1)。
4的位串表示是100,8是1000,最好将这些读作“一零零”和“一零零零”,而不是“一百”、“一千”等。6是2+4,或110=010+100。下面是上述属性值的位串:
00 = 0000000
01 = 0000001
02 = 0000010
04 = 0000100
08 = 0001000
16 = 0010000
32 = 0100000
64 = 1000000
因为上表中的每个值都是2的幂,所以位串表示中的所有位除了其中一个外都为零。为此,将这些数字中的任何一个加在一起永远不会“翻转一位”并延续到下一列,因为每个数字都在其自己的列中完全表示。
要查看4是否是6的“一部分”,可以检查4中的每个1位是否在6中都有对应的1位。记住这是按位运算,因此我们需要逐列进行:
06 = 0000110
AND
04 = 0000100
xx = 0000100 <-- 按位输出,其中顶行和底行中的位均为1
在右边的第三列,也就是4的指定列,我们在6中有一个1位,按位AND运算符输出产生一个非零数,因此4,vbSystem,是6的一部分。如果我们有14(2+4+8),你能怎样计算来确定是否存在vbArchive?
如果总和的可能输入不是2的幂,则此技巧不起作用。
小结
VBA的GetAttr函数使用求和技术提供有关文件属性的信息,该技术为每个属性组合提供唯一编号。同时,VBA的GetAttr函数是一个函数,而不是文件属性,因此不能使用它来更改文件属性,只能使用它来确定存在哪些文件属性。
可以使用按位AND运算符确定是否存在特定属性。按位运算是逐位进行的,而不是将位串视为一个整体,并且属性的十进制表示中的间隙使按位AND能够检测属性是否为真。
注:本文整理自wellsr.com,供有兴趣的朋友参考。