嗨,Scripting Guy!
欢迎来到这个全新的 TechNet 专栏,在这里,Microsoft Scripting Guys 将为您解答与系统管理脚本编写有关的各种常见问题。遇到了系统脚本编写方面的问题?请将电子邮件发送到:scripter@microsoft.com. 我们不保证能够回答所有问题,但一定会尽我们所能为您排忧解难。
今天的问题:怎样才能创建一个 CSV 文件?
怎样才能创建一个 CSV 文件?
问:
嗨,Scripting Guy!怎样才能创建一个 CSV 文件?
-- LF
答:
嗨,LF。致那些不太了解缩写的人:CSV 是逗号分隔值 (comma-separated-values) 文件的缩写,这是一种使用逗号来分隔各个元素的文本文件。例如,假设您具有一个由用户的姓、名和职称组成的 CSV 文件,那么这个文件的内容可能类似如下:
Ken,Myer,Accountant Pilar,Ackerman,Vice-President Carol,Philips,Research Specialist
顺便提一句,在 Microsoft 我们喜欢使用缩写。比如说吧,前几天 Scripting Guy 就收到过由 11 个缩写组成的三个句子的产品说明。我们的个人爱好——其实这里的人都有这个爱好——是 OOF,就是 Out Of Office 的缩写(即放假的意思)。
一点都不奇怪,我们感到有必要在我们的所有产品中增加一个拼写检查器。
但算了,还是回到您的问题上来吧。怎样才能创建一个 CSV 文件呢?很简单:使用 FileSystemObject。毕竟,它就是用来干这个的。
让我们先来看一段非常简单的验证脚本,然后我们将介绍一个较为实用的示例。以下示例脚本可将字符串 A,B,C 写入名为 Test.csv 的文本文件中:
Const ForWriting = 2
Set objFSO = CreateObject ( " Scripting.FileSystemObject " )
Set objLogFile = objFSO.CreateTextFile( " test.csv " , _
ForWriting, True )
objLogFile.Write " A, "
objLogFile.Write " B, "
objLogFile.Write " C "
objLogFile.Writeline
objLogFile.Close
我们首先定义一个名为 ForWriting 的常量,并将它的值设置为 2;不管在什么时候使用 FileSystemObject,您都需要使用适当的常量,这取决于您想要读取、写入或是追加一个文件。我们创建一个 FileSystemObject 实例,然后使用 CreateTextFile 方法来创建一个名为 Test.cvs 的新文本文件。(请注意,我们没有指定路径,这意味着这个文本文件会创建在与脚本相同的文件夹中。如果愿意的话,我们也可以指定一个完整路径,例如 C:/Scripts/Logfiles/Test.csv。)
当我们调用 CreateTextFile 方法时,我们同时创建了一个指向新文件的对象引用;在脚本中,我们将这个对象引用命名为 objLogFile(也可以命名为其他名称)。有了对象引用,我们就可以使用 Write 方法将数据写入文件中。请注意,我们从字符串 A, 开始写入(对了,创建 CSV 文件时我们必须手动写入逗号)。Write 方法会写入指定的数据(上述示例中即为 A,),并将光标置于当前位置。因此,下一次调用此方法时,字符串 B, 恰好位于字符串 A, 的右侧。最后得到的文本文件如下:
A,B,
我们第三次调用 Write 方法,并写入 C。由于这标记这一行的结尾,因此我们不必在其后附加一个逗号,而是调用 WriteLine 方法,这个方法等同于点按键盘上的 ENTER 键。最后得到的文本文件如下:
A,B,C
注意逗号和下一个项目之间没有任何空格。一个项目结束时,另一个项目马上开始。
现在,让我们来看一个较为实用的示例。这个脚本使用 WMI 来检索服务信息,然后使用 FileSystemObject 将这些信息写入名为 Service_List.csv 的文本文件中:
Const ForAppending = 2
Set objFSO = CreateObject ( " Scripting.FileSystemObject " )
Set objLogFile = objFSO.CreateTextFile( " service_list.csv " , _
ForWriting, True )
strComputer = " . "
Set objWMIService = GetObject ( " winmgmts: " _
& " {impersonationLevel=impersonate}!/ " & strComputer & " ootcimv2 " )
Set colListOfServices = objWMIService.ExecQuery( " Select * from Win32_Service " )
For Each objService in colListOfServices
objLogFile.Write objService.Name & " , "
objLogFile.Write objService.StartMode & " , "
objLogFile.Write objService.State
objLogFile.Writeline
Next
objLogFile.Close
如您所见,我们使用了和验证脚本中相同的技术。最大的差别在于,我们不使用类似于 A, B, 和 C 的硬编码值,而是使用类似于 objService.Name 的变量。那不是问题,我们只需使用这个变量作为 Write 方法的参数即可。由于这些是变量,因此我们无法使用双引号将它们和其后的逗号括起来。以下这行代码不能工作:
objLogFile.Write "objService.Name,"
我们转而指定变量 (objService.Name),然后使用 & 符号来将逗号 (“,”) 附加到结尾。我们对 StartMode 执行相同的任务,但不对 State 执行;因为 State 是每行的最后一个项目。因此,我们使用 WriteLine 来按 ENTER 键,并在文件中开始新行(和我们第一个示例中在字母 C 后面使用 WriteLine 的方法一样)。由于我们在一个 For Each 循环内部执行这个操作,因此我们将以对计算机上安装的每一个服务编写此信息来结束。
最后得到的文本文件如下:
Alerter,Manual,Stopped ALG,Manual,Stopped AppMgmt,Manual,Stopped aspnet_admin,Auto,Stopped
尽管我们可以稍微减少一点代码行的数量(通过串联所有变量和 what-not),但是将代码写成这种样式比较便于您理解代码的作用。同时这也便于您在每行中添加新项目。想要包含服务 PathName?那就添加以下一行代码:
objLogFile.Write objService.PathName & ","
还有一个事情:当您使用 WMI 时,前一个脚本可能可以处理您的全部需要。但是当使用其他脚本技术时,使用包含逗号的数据您可能会遇到问题。例如,假设您有一个用户、他们的办公室地址和职称的文本文件。一个用户的地址为 2049,而另一个用户的地址为 2050, Suite A。这样,您的文本文件看来应该类似如下:
Ken,Myer,2049,Accountant Pilar,Ackerman,2050,Suite A,Vice-President
呀!我们遇到了一个问题:第一行包含四个字段(记住逗号表示一个字段的结束和下一个字段的开始):Ken / Myer / 2049 / Accountant.但不幸的是,由于地址中包含逗号,第二行代码中却具有五个字段:Pilar / Ackerman / 2050 / Suite A / Vice-President.喔噢……。
如何处理类似这种嵌入式逗号的问题呢?秘诀就是使用一个双引号包含每个字段;如果您的文本文件类似如下所示,那么嵌入式逗号就会被忽略:
"Ken","Myer","2049","Accountant" "Pilar","Ackerman","2050,Suite A","Vice-President"
那么,如何使用双引号来包含字段呢?以下是另一个示例脚本,这个脚本使用函数 Chr(34) 来写入双引号,接着写入服务属性(例如 objService.Name),使用 Chr(34) 来写入另一个双引号,然后 才在结尾附加一个逗号。
Const ForWriting = 2
Set objFSO = CreateObject ( " Scripting.FileSystemObject " )
Set objLogFile = objFSO.CreateTextFile( " service_list.csv " , _
ForAppending, True )
strComputer = " . "
Set objWMIService = GetObject ( " winmgmts: " _
& " {impersonationLevel=impersonate}!/ " & strComputer & " ootcimv2 " )
Set colListOfServices = objWMIService.ExecQuery( " Select * from Win32_Service " )
For Each objService in colListOfServices
objLogFile.Write chr ( 34 ) & objService.Name & chr ( 34 ) & " , "
objLogFile.Write chr ( 34 ) & objService.StartMode & chr ( 34 ) & " , "
objLogFile.Write chr ( 34 ) & objService.State & chr ( 34 )
objLogFile.Writeline
Next
objLogFile.Close
有关更多信息,请参阅“Microsoft Windows 2000 脚本指南”中的 相应部分。并且我们已经知道了您的下一个问题:如何使用脚本来读取 CSV 文件?若要知道答案,请在阅读文本文件时使用 ADO 访问此“脚本诊所”专栏。