【问题标题】:Copy most recent file from a batch of alike files using vbscript使用 vbscript 从一批相似文件中复制最新文件
【发布时间】:2012-02-02 17:50:08
【问题描述】:

我不确定这是否可能。我什至不知道从哪里开始。我有几千个文件,其中的文件名是这样命名的:

nnnnnnnnnnnnnnnn.yyyyddmm.pdf(n = 数字,yyyy = 年,dd = 日,mm = 月)。

在这数千个文件中,有一批相似的文件具有相同的nnnnnnnnnnnnnnnnnn 部分文件名但.yyyyddmm 不同以表示文件的日期。 (这些批次的相似文件将在稍后合并在一起,但这对这种情况并不重要)。

我的问题是,有没有办法比较相似文件的yyyyddmm 部分,并将最近的日期文件复制到不同的文件夹?我需要将文件名上类似文件的最新日期的文件复制到不同的文件夹中。

我遇到此问题的原因是因为我不确定是否可以比较文件名的各个部分以查看哪个实际上是具有最新日期的文件。我知道有一种方法可以通过查看日期修改日期来完成,但这并不总是给我最近日期的相似文件。

有什么想法吗??如果我能提供更多信息,请告诉我。

【问题讨论】:

    标签: vbscript


    【解决方案1】:

    试图了解您的问题/规格。假设对 .pdf 文件夹的文件进行循环会导致:

    Looking at "0000000000012345.20120402.pdf"
    Looking at "0000000000012345.20120502.pdf"
    Looking at "0000000000012348.20121702.pdf"
    Looking at "0000000000012346.20120802.pdf"
    Looking at "0000000000012347.20121002.pdf"
    Looking at "0000000000012348.20121602.pdf"
    Looking at "0000000000012347.20121302.pdf"
    Looking at "0000000000012347.20121202.pdf"
    Looking at "0000000000012345.20120202.pdf"
    Looking at "0000000000012348.20121502.pdf"
    Looking at "0000000000012346.20120602.pdf"
    Looking at "0000000000012346.20120902.pdf"
    Looking at "0000000000012348.20121402.pdf"
    Looking at "0000000000012346.20120702.pdf"
    Looking at "0000000000012347.20121102.pdf"
    Looking at "0000000000012345.20120302.pdf"
    

    Last file for 0000000000012345 is 0000000000012345.20120502.pdf
    Last file for 0000000000012348 is 0000000000012348.20121702.pdf
    Last file for 0000000000012346 is 0000000000012346.20120902.pdf
    Last file for 0000000000012347 is 0000000000012347.20121302.pdf
    

    确定要正确复制的文件?如果是,请说出来,我会在此处发布代码。

    首先,您需要一个类来获取并存储放入文件名中的信息:

    ' cut & store info about file(names) like "0000000000012347.20121202.pdf"
    Class cCut
      Private m_sN  ' complete file name
      Private m_sG  ' group/number prefix part
      Private m_dtF ' date part; converted to ease comparisons
      Public Function cut(reCut, sFiNa)
        Set cut = Me ' return self/this from function
        Dim oMTS : Set oMTS = reCut.Execute(sFiNa)
        If 1 = oMTS.Count Then
           m_sN  = sFiNa
           Dim oSM : Set oSM = oMTS(0).SubMatches
           m_sG  = oSM(0)
           m_dtF = DateSerial(oSM(1), oSM(3), oSM(2))
        Else
           ' Err.Raise
        End If
      End Function ' cut
      Public Property Get G() : G = m_sG  : End Property ' G
      Public Property Get D() : D = m_dtF : End Property ' D
      Public Property Get N() : N = m_sN  : End Property ' N
    End Class ' cCut
    

    然后只需遍历 .Files 并检查存储在字典中的每个组的日期部分(数字前缀部分用作键):

      ' The one and only .pdf folder - no recursion into subfolders!
      Dim sTDir : sTDir     = "..\data\test"
      ' dictionary to store the last/most recently used file for each group
      Dim dicG  : Set dicG  = CreateObject("Scripting.Dictionary")
      ' RegExp to cut/parse file names like "0000000000012345.20120402.pdf"
      Dim reCut : Set reCut = New RegExp
      reCut.Pattern = "^(\d{16})\.(\d{4})(\d{2})(\d{2})\.pdf$"
      Dim oFile
      For Each oFile In goFS.GetFolder(sTDir).Files
          WScript.Echo "Looking at", qq(oFile.Name)
          ' an oCut object for each file name
          Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
          If Not dicG.Exists(oCut.G) Then
             ' new group, first file, assume this is the latest
             Set dicG(oCut.G) = oCut
          Else
             ' found a better one for this group?
             If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
          End If
      Next
      WScript.Echo "-----------------------"
      Dim sG
      For Each sG In dicG.Keys
          WScript.Echo "Last file for", sG, "is", dicG(sG).N
      Next
    

    WRT cmets:

    我所有的(临时/概念证明)脚本都以

    开头
    Option Explicit
    Dim goFS     : Set goFS = CreateObject( "Scripting.FileSystemObject" )
    

    并包含一些处理不同方面/策略的函数,以解决常见问题/主题。当我在这里发布代码时,我会从函数框架的中间复制/粘贴工作/测试代码,例如

    ' ============================================================================
    goXPLLib.Add _
      "useDic02", "use a dictionary (Mark II)"
    ' ----------------------------------------------------------------------------
    ' ============================================================================
    Function useDic02()
      useDic02 = 1 ' assume error
    
      ' The one and only .pdf folder - no recursion into subfolders!
      ...
      Next
    
      useDic02 = 0 ' success
    End Function ' useDic02
    

    (是的,有一个第一次尝试函数“useDic()”,它存储了每个组的所有 oCuts,以便在第二个循环中处理;是的,我需要一个函数“createTestData()”设置/填写我的 TDir)。有时我很马虎,忘记了goFS,请接受我的道歉。

    变量名称是实验的一部分。我曾经提倡以类型为前缀的长变量名,包括

    Dim nIdx
    For nIdx = 0 To UBound(aNames)
        aNames(nIdx) = ...
    Next
    

    其他人认为 nIdx-alikes 变量只是添加了一些字母以错误输入,但对 i 没有其他含义,并且 aNames-alikes 不能在没有上下文的情况下被理解,如果你有这个,aN 会一样好“当前处理文件中要与数据库中的名称进行比较的波斯国王的名字”的余数。

    所以我想:鉴于文件名有 3 个有趣的方面(要复制的全名、要复制的全名、要分组的数字前缀、要比较/决定的日期部分)并且之间有半个屏幕

      Private m_sN  ' complete file name
    

      Public Property Get N() : N = m_sN  : End Property ' N
    

    假设您只需要 Cut 对象的这 3 个属性就可以在其中使用它

      Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
      If Not dicG.Exists(oCut.G) Then
         ' new group, first file, assume this is the latest
         Set dicG(oCut.G) = oCut
      Else
         ' found a better one for this group?
         If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
    

    平均短时记忆能否应对 oCut.D?

    显然不是。

    复制所选文件:

    假设您希望将文件复制到现有文件夹“..\data\latest”,请使用

    goFS.CopyFile goFS.BuildPath(sTDir, dicG(sG).N), "..\data\latest\", True
    

    代替/除了线

    WScript.Echo "Last file for", sG, "is", dicG(sG).N
    

    我没有预料到 .CopyFile 会在相对源路径上阻塞;所以考虑用 *P*ath 属性替换 cCut 类的 *N*ame 属性。

    尝试使用

    dicG(sG).Copy "..\data\latest\", True
    

    结果:

    Microsoft VBScript runtime error: Object doesn't support this property or method: 'dicG(...).Copy'
    

    因为存储的对象不是文件(有 .Copy 方法),而是 cCuts(没有)。

    【讨论】:

    • 是的,这正是我要找的。我真的很想看看这是如何处理的。
    • +1 用于类的使用。但是哦,伙计,你的变量命名。我花了多次上下滚动来重新映射它们在我的脑海中。你知道自从引入 GW-BASIC 以来,我们最多可以为一个变量使用 40 个字符吗? :)
    • 感谢脚本。变量有点难以映射。我收到 goFS 的对象错误,因为它没有定义。
    • 应该如何定义goFS来让脚本执行?这段代码我很难理解。
    • 哇,这个脚本运行起来就像一个魅力!!!!现在,如果我想复制存储在 dicG 中的每个文件而不是显示消息,那么该代码会是什么样子?我尝试了几件事,但都没有成功。这本字典的东西对我来说是新的,而且非常混乱。这是我最新尝试的: Dim sG Dim newpath: newpath = "newfolder" For Each sG In dicG.Keys dicG(sG).Copy newpath Next
    【解决方案2】:

    我会怎么处理:

    1. 我会制作一个字典,其中每个唯一数字部分都有一个单独的键。该值将是一个数组,其中所有文件名共享该键(因此共享唯一编号部分)

    2. 对于字典中的每个键,我将遍历数组中的项目,搜索最近的日期。

    方法:

    1. 获取文件
    2. 提取数字部分
    3. 查看该数字部分的键是否存在。如果不使用空数组作为值创建该数字的键
    4. 将文件名作为新项目添加到数组中
    5. 循环到 1。直到处理完所有文件

    6. 获取密钥

    7. 获取附加数组中的第一个文件。记住日期和数组索引
    8. 获取下一个文件,如果日期高于记住的日期,更新日期到这个日期,arrayindex更新到这个数组索引
    9. 循环到 8. 直到到达数组的末尾
    10. 将带有数组索引的文件存储为该唯一编号的最新文件
    11. 循环到 6。直到处理完所有键

    【讨论】:

    • 字典+1;但是,如果您对(结构化)集合的“限制项目”(最小的、最新的……)感兴趣,则无需保留候选人 - 只需比较/存储/更新“迄今为止最好的”。然后你就可以一次性解决问题了。
    • 是的,我同意一次性通行证。尽管同时做两件事会使解释变得更复杂。
    • 我不确定您所说的创建字典和密钥是什么意思?我知道如何将项目放入数组中。
    • 字典就像一个数组,但具有唯一键(字符串)作为下标而不是整数。就像数组一样,属于键的值也可以是数组。字典的接口也比数组更容易。如何使用数组可以阅读allovertheinternet
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 2014-10-29
    • 1970-01-01
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2013-09-13
    相关资源
    最近更新 更多