来自 LotusScript 代理的运行时错误 53 "File Not Found"(已解决)

Runtime Error 53 "File Not Found" from LotusScript agent (SOLVED)

由于未知原因,服务器端 LotusScript 代理在尝试读取现有邮件存档文件的物理文件大小时抛出错误 53“找不到文件”。情况如下:

LS 代理正在循环服务器“\Data”目录下给定目录“\archive”中的所有文件。有问题的服务器是 Windows 2016 服务器上的 Domino 10.0.1 运行。 LS 代码在目录中循环查找名称遵循给定模式(如“a_EmployeeID.nsf”的数据库文件。如果 DB 的文件名符合模式,则代码使用文件名中的 EmployeeID 扫描服务器的 names.nsf 以查找存档所有者。如果没有找到该 ID 的个人文档,代码将尝试使用 FileLen(filePath & FileName) 读取数据库的物理文件大小。然后将生成的数据(文件路径 + 文件大小)+ EmployeeID 写入磁盘上的报告文件。不遵循该模式的文件也至少会写回到报告中。该代理背后的想法是找到“孤立的”或放错地方的数据库。

对于大约 80% 的扫描文件,此方法工作正常,具有确切文件大小的记录将写入报告。但对于其他 ~20% 的运行时间,error 53 "File not found" 拉高了。在那些情况下,记录仅包含文件 path/name + EmployeeID(如果可用)+ 文件大小的“-1”。因为文件显然确实存在,所以我认为这是访问或安全问题。

代理使用管理员 ID 签名,管理员 ID 在服务器和相关存档文件上具有最大访问权限(策略 ID 在 dbs 的 ACL 中具有管理员访问权限)。 代理的安全设置设置为 3 级(具有完全管理权限的无限制访问),因为我首先使用在服务器上具有完全管理访问权限的 ID 对代理进行签名(与现在使用的 ID 的结果相同)。

比较数据库的 ACL,我找不到“有效”和“无效”的 ACL 之间的任何区别。不过,我看到的是,显然总是相同的数据库引发此错误,因此这不是随机问题。

为了完整起见,这里是代理代码的关键部分:

sFileName = Dir$(sPath & "*.nsf")
Do Until sFileName = ""
    iCount = iCount + 1
    sEmpid = "" 'reset
    lSizeArc = 0 'reset
    dblSizeArc = 0 'reset
    sSizeArcFmt = "" 'reset
    If(sFileName Like sPattern) Then
        sEmpid = Left(Right(sFileName, Len(sFileName) - 2), 6)
        Set vec = vwEgid.Getallentriesbykey(sEmpid, True)
        If(vec.count = 0) Then
            On Error 53 Resume Next 'Error 53 ("File not found")
            lSizeArc = FileLen(sPath & sFilename)
            If(Err = 53) Then
                lSizeArc = -1
                sSizeArcFmt = "-1 (no size available)"
                Err = 0
            Else
                dblSizeArc = Round((lSizeArc / 1024 / 1024), 3)
                sSizeArcFmt = Format$(dblSizeArc, "0.000") & " MB"
            End If
            Print #iFileNum,_
                "ORPHANED_ARCHIVE;" & sEmpid & ";" & sFileName & ";" & sSizeArcFmt
        End If
    Else
        On Error 53 Resume Next 'Error 53 ("File not found") 
        lSizeArc = FileLen(sPath & sFilename)
        If(Err = 53) Then
            lSizeArc = -1
            sSizeArcFmt = "-1 (no size available)"
            Err = 0
        Else
            dblSizeArc = Round((lSizeArc / 1024 / 1024), 3)
            sSizeArcFmt = Format$(dblSizeArc, "0.000") & " MB"
        End If
        Print #iFileNum,_
            "BAD_FILE_PATTERN;NO_EGID;" & sFilename & ";" & sSizeArcFmt
    End If
    sFileName = Dir$() 'next file
Loop 

在我开始转向不同的方向之前,例如研究使用 Windows shell 或 .dll 命令,我真的很想了解为什么在某些情况下代码坚持某些文件看着无法“找到”。

有什么想法吗?

更新 2021-05-19

所以我终于找到了解决这个问题的方法(我承认,这并不是对我的编程技能的赞美): 再次查看抛出错误 53 的文件,我意识到它们都相当大,确切地说 > 2.1 GB。所以我不得不承认我犯了一个愚蠢的编程错误:当然,将一个大小的值分配给一个 LONG 变量是行不通的。愚蠢的业余错误... (但是为什么代码没有像通常那样抛出正确的错误来告知值超出限制?) 无论如何,所以我将变量更改为 DOUBLE。 但是:结果仍然相同,尽管 >> 错误 53。 然后再次查看设计器帮助我发现了这个小注释:

FileLen returns a Long value

换句话说:FileLen 本身无法处理那么大的文件,而且在解释器发现我的错误编码之前显然会抛出该错误。 换句话说:没有办法那样解决我的问题。回到@TorstenLink 的评论:我现在就用他的方法

非常奇怪的错误信息,我还是要说...

感谢大家帮我思考;)

由于您只从磁盘读取:DIR 和 FileLen,因此您不会在文件上遇到 Domino LOCK(但不要尝试写入!)

我建议您更改代码以确定它落在何处以及落在哪些文件上:

f(vec.count = 0) Then
        placeInCode = 1 'declare this before as int
        On Error 53 Resume goto handelError'Error 53 ("File not found")

第二部分,影响placeInCode = 2

然后声明一个

handelError:
    print "we got error 53 on " & sPath & sFilename & " for the " & placeInCode & " part"
    resume next

LotusScript 可能正在调用 32 位 WinAPI 以获得 file-length 并且此调用将返回一个无符号的 32 位值,最大文件大小为 ~4.2Gb .但是,LS 不支持无符号的 32 位值,仅支持有符号的值,因此返回的任何超过 2.1Gb 的值都由负值表示。

您可以取负值的绝对值并将其换算成货币或 single/float,再加上 2.1Gb 得到 file-size 最多 4.2Gb,但不会更大,因为API 调用不会返回更大的数字,因此,API 调用可能不认为这是一个错误,并且 LS 在技术上没有 'overflowed' 生成大小错误。

或者,如果您将超过 1Gb 的任何大小视为 'reportable',只需查找 +ve 和 > 1gb 或 < 0 的值,因为任何负值都表示 'big'。我猜确切的文件大小对您来说并不那么重要。