今天日本的客户来了一个要求,
他想要一个报表, 包含我们程序安装目录下的所有文件, 以及这些文件的版本信息.
看了一下, 安装路径下共有上千个文件,
看来这个问题人是搞不定了, 正好写一个ruby脚本.
在下面这篇博客里面已经介绍了遍历文件夹的操作.
Ruby练习贴01: 遍历两个文件夹, 删除那些名字相同, 内容也相同的文件
所以剩下的问题就是如何取得一个文件的版本信息了
(如果这个文件存在版本信息的话, 一般dll, exe文件都有版本信息, 但是txt这些文件一般就都没有了.)
为了解决这个问题, 需要使用ruby的Win32API.
可以参考的连接有, 其中第二个连接中还包含Win32API的其他的一些例子:
Microsoft Windows Support@Programming Ruby - The Pragmatic Programmer's Guide
Checking version of file in Ruby on Windows@stackoverflow
解决这一问题的脚本如下, 调用get_version函数, 直接返回该文件所对应的版本信息.
require "Win32API" def get_version (filename) s="" vsize = Win32API.new('version.dll', 'GetFileVersionInfoSize',['P', 'P'], 'L').call(filename, s) #p vsize if (vsize > 0) result = ' '*vsize Win32API.new('version.dll', 'GetFileVersionInfo',['P', 'L', 'L', 'P'], 'L').call(filename, 0, vsize, result) rstring = result.unpack('v*').map{|s| s.chr if s<256}*'' r = /FileVersion..(.*?)\000/.match(rstring) #puts "FileVersion = #{r ? r[1] : '??' }" ver = r[1] else ver = "" end end target1 = 'C:\Program Files (x86)\Microsoft F#\v4.0\Fsc.exe' target2 = 'C:\Windows\DirectX.log' target3 = 'C:\Windows\notepad.exe' puts get_version target1 puts get_version target2 puts get_version target3
Ruby还有这么一个gem, win32-api.
他是Win32API的一个替代品.
他们之间的区别可以参考下面的连接
http://rubydoc.info/gems/win32-api/1.4.8/frames
最后,贴出这个应用的完整代码,
遍历特定文件夹, 显示所有文件的相对文件名, 以及他们的版本信息.
require "fileutils" require "pathname" require "Win32API" def get_version (filename) s="" vsize = Win32API.new('version.dll', 'GetFileVersionInfoSize',['P', 'P'], 'L').call(filename, s) #p vsize if (vsize > 0) result = ' '*vsize Win32API.new('version.dll', 'GetFileVersionInfo',['P', 'L', 'L', 'P'], 'L').call(filename, 0, vsize, result) rstring = result.unpack('v*').map{|s| s.chr if s<256}*'' r = /FileVersion..(.*?)\000/.match(rstring) #puts "FileVersion = #{r ? r[1] : '??' }" ver = r[1] else ver = "" end end target_dir = "C:/Program Files (x86)/my-install-folder" Dir.glob("#{target_dir}/**/*") do |item| next if File.directory? item relative_path = Pathname.new(item).relative_path_from(Pathname.new(target_dir)) info = "#{relative_path}\t\t#{get_version item}" puts info end