【问题标题】:How can I get rid of wait time between 2 methods that access the same file?如何摆脱访问同一文件的两种方法之间的等待时间?
【发布时间】:2011-01-03 12:22:13
【问题描述】:

我有以下一段 VBSCript 代码来在纯文本文件中查找一个部分 (strSection) 和该部分中的一个项目 (strItem)。

Do While Not myINIFile.AtEndOfStream
  sl_Sleep(100)
  s = myINIFile.ReadLine <--- **This is the line that rises the exception**
  If s = strSection Then
    'Find the correct line
    Do While Not myINIFile.AtEndOfStream
      s = myINIFile.ReadLine
      If InStr(s, strItem)>0 Then
        Exit Do
      End if              
    Loop            
    Exit Do
  End if              
Loop 

看来,如果我不设置 Sleep(100)(毫秒)(或使用较低的值,如 20 或 50),我最终会收到一个异常,提示“该进程无法访问文件,因为另一个进程已锁定一部分文件”。

我认为 Do While 中的条件是在 AtEndOfStream 尚未完成时正在调用 ReadLine 方法。但是,对每条线路使用 100 毫秒会使该过程减慢到无法接受的速度。

这是真正发生的事情还是其他地方的问题? 我可以做些什么来防止这个进程被锁定或等待多一点(直到它被释放)只有如果它被锁定所以它不会引发异常?


编辑:这段代码循环通过一个看起来像这样的文件:

[Section1]    
param1 = 100    
param2 = 200    
param3 = 300    

[Section2]    
param1 = 1000    
param2 = 2000    
param3 = 3000

[Section3]    
param1 = 1
param2 = 2
param3 = 5
param4 = 10
param5 = 20

代码应该遍历文件,直到找到 [SectionX] 行 (strSection),然后继续读取行,直到找到“paramx”行 (strItem)。然后将这一行保存在 's' 中,稍后进行处理。

【问题讨论】:

  • 这段代码有效吗?看一眼,看起来你正在循环一个文件流直到你得到一个匹配,然后你又循环了同一个流。令人困惑的是,它似乎没有做任何事情,一旦您找到与您正在寻找的内容匹配的行,它就会简单地退出循环。我认为,如果您发布了您尝试解析的数据样本,它可能会有所帮助。
  • 代码工作,虽然它有这种瓶颈。有关详细信息,请参阅编辑后的说明。
  • 我同意@unrealtrip,你有两个循环,但都从同一个流对象中读取,所以它不应该锁定流。您是否在调用此函数之间正确关闭了流?
  • 您发布的代码无法使用。您正在按照错误所说的进行操作并尝试循环相同的流。看看我在下面发布的简单循环应该可以解决问题。

标签: file exception process vbscript locked


【解决方案1】:

您发布的代码非常适合我。我没有例外...

您在使用您发布的代码时是否在其他任何地方访问该文件?

您是否尝试过读取整个文件然后解析字符串?见http://www.motobit.com/tips/detpg_asp-vbs-read-write-ini-files/

【讨论】:

  • 我发布的文件就是一个例子。我拥有的文件比那个大得多(25 到 35 KB)。该代码将起作用,问题是 Sleep(100) 行使它比我想要的慢得多。但是,如果我在某个时候取出睡眠线(或将其减少到 50 毫秒),Readline 命令中就会出现此异常。
  • 尝试只使用一次“Do While Not myINIFile.AtEndOfStream”。所以你只有一个循环,然后在找到该部分时设置一个变量,在找到参数时设置第二个变量。这两个变量可以用作循环的退出条件
  • 直到找到该部分(参见前面的 IF 语句)之后,我才会进入第二个循环,然后我有一个“Exit Do”,然后是另一个“Exit Do”。问题是我在某些时候要查找的部分位于文件末尾
  • 显然我正在测试的主应用程序仍在访问此文件(尽管我不确定为什么以及是否应该这样做)。
【解决方案2】:

给你,这段代码将执行循环。您遇到的问题是对同一流重复使用 readline,并且它正在读取 EOF(和/或)创建文件锁定争用。

Const TristateFalse = 0
Const ForReading = 1

strINIfile = "c:\scripts\testconfig.ini"
strSection = "[Section2]"
strItem = "param3"

Set objFSO = WScript.CreateObject("Scripting.Filesystemobject")
Set objINIstream = objFSO.OpenTextFile(strINIfile, ForReading, False, TristateFalse)

boolCheckSection = False

Do While Not objINIstream.AtEndOfStream
    strLine = Trim(objINIstream.ReadLine)

    ' Determine if we're in the section, set boolcheck if so
    If InStr(UCase(strLine),UCase(strSection)) Then     
        boolCheckSection = True     
    ElseIf InStr(UCase(strLine), "[") Then  
        boolCheckSection = False
    End If

    ' If so, read the proper value and store in variable
    If boolCheckSection Then
        If InStr(UCase(strLine), UCase(strItem)) Then
            tmpParam = Split(strLine, "=")
            strParamValue = Trim(tmpParam(1))
            Exit Do ' exit loop with set variable
        End If      
    End If

Loop

WScript.Echo strParamValue

【讨论】:

  • 这段代码当然不包括错误捕获,也不是作为函数设置的,它只是工作代码。您需要对其进行修改以在您的程序范围内工作。
【解决方案3】:

函数 ReadIni(myFilePath, mySection, myKey) ' 此函数返回从 INI 文件中读取的值 ' ' 论据: ' myFilePath [string] INI 文件的(路径和)文件名 ' mySection [string] INI 文件中要搜索的部分 ' myKey [string] 要返回其值的键 ' ' 返回: ' 指定节中指定键的 [string] 值 '

Const ForReading   = 1
Const ForWriting   = 2
Const ForAppending = 8

Dim intEqualPos
Dim objFSO, objIniFile
Dim strFilePath, strKey, strLeftString, strLine, strSection

Set objFSO = CreateObject( "Scripting.FileSystemObject" )

ReadIni     = ""
strFilePath = Trim( myFilePath )
strSection  = Trim( mySection )
strKey      = Trim( myKey )

If objFSO.FileExists( strFilePath ) Then
    Set objIniFile = objFSO.OpenTextFile( strFilePath, ForReading, False )
    Do While objIniFile.AtEndOfStream = False
        strLine = Trim( objIniFile.ReadLine )

        ' Check if section is found in the current line
        If LCase( strLine ) = "[" & LCase( strSection ) & "]" Then
            strLine = Trim( objIniFile.ReadLine )

            ' Parse lines until the next section is reached
            Do While Left( strLine, 1 ) <> "["
                ' Find position of equal sign in the line
                intEqualPos = InStr( 1, strLine, "=", 1 )
                If intEqualPos > 0 Then
                    strLeftString = Trim( Left( strLine, intEqualPos - 1 ) )
                    ' Check if item is found in the current line
                    If LCase( strLeftString ) = LCase( strKey ) Then
                        ReadIni = Trim( Mid( strLine, intEqualPos + 1 ) )
                        ' In case the item exists but value is blank
                        If ReadIni = "" Then
                            ReadIni = " "
                        End If
                        ' Abort loop when item is found
                        Exit Do
                    End If
                End If

                ' Abort if the end of the INI file is reached
                If objIniFile.AtEndOfStream Then Exit Do

                ' Continue with next line
                strLine = Trim( objIniFile.ReadLine )
            Loop
        Exit Do
        End If
    Loop
    objIniFile.Close
Else
    WScript.Echo strFilePath & " doesn't exists. Exiting..."
    Wscript.Quit 1
End If

结束函数

【讨论】:

  • 有时间我会试试这个,但是有几个地方有一个 AtEndOfStream 后跟一个 ReadLine,所以我真的想知道这是否会有所不同......
  • 这是非常难以阅读的六级深度嵌套 do/loop,if/then 块,它也使用对文件流的多个 readline 调用并且是非功能代码。
  • 这是理所当然的工作 - 只需复制粘贴你应该能够做到这一点。它只是被stackoverflow格式错误...
  • 问题与格式无关,与代码编写不当无关。您对同一个文件流进行了多次 readline 调用,这可能会导致您读取超过 EOF 并崩溃的争用。
【解决方案4】:

感谢大家的回复。查看您提出的代码并研究它们让我意识到我自己的代码首先没有任何问题(即使有 2 个 while 循环,它也正确退出了它们)。在尝试了您提出的代码之后,我仍然发现它在我的测试用例中随机断言,并且在考虑之后我意识到我正在测试的主要应用程序仍然访问了这个文件(虽然我不知道为什么,但那是另一回事)。

我找到的解决方案是我们在手动测试时总是建议的解决方案;复制原件并在副本上工作。

另外,感谢您提出的代码,他们给了我不同的角度来改进我的代码设计和可读性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 2023-04-01
    • 2011-01-31
    • 1970-01-01
    相关资源
    最近更新 更多