【问题标题】:Vbscript - Read ini or text file for specific sectionVbscript - 读取特定部分的 ini 或文本文件
【发布时间】:2011-03-30 08:23:49
【问题描述】:

我想将一些地址存储在文本文件中,然后根据组成员身份读取文件的特定部分。我已经完成了所有组成员身份的工作,所以我不需要任何帮助。

但我不确定我应该使用纯文本文件还是 INI 文件?
问题是,帖子地址在两三行,我需要换行。
我尝试使用纯文本文件,但无法正确换行。

那么 INI 文件会更好吗?

INI 文件可能如下所示:

[伦敦] 地址1 邮箱 3245 58348 伦敦 [哥本哈根] 地址2 邮箱 2455 5478347 哥本哈根

我不太确定这在 INI 文件中是否可行,也许我还需要为每一行命名。或者,我可以使用纯文本文件并搜索单词 [london],然后读取每一行,直到出现换行符。然后将所有这些行存储在我将传递的变量中?

你们会怎么解决这个问题?

【问题讨论】:

    标签: vbscript ini


    【解决方案1】:

    我使用一个小型可执行文件来启动本机 api:GetPrivateProfileStringWritePrivateProfileString

    可执行文件是这样调用的:

    Set sh = CreateObject("WScript.Shell")
    Set exec = sh.Exec("ini.exe get %APPDATA%\sth\file.ini ""Section name"" key")
    sFirma1 = exec.StdOut.ReadLine
    Call sh.Run("ini.exe set %APPDATA%\sth\file.ini ""Section name"" key set_value", 0)
    

    另见Running command line silently with VbScript and getting output?

    这是可执行文件的代码:

    #include <stdio.h>
    #include <windows.h>
    
    void usage()
    {
      puts("ini <get>/<set> <file> <section> <key> <value>");
      exit(1);
    }
    
    int main(int cArg, char **aszArg)
    {
      int iFile = 2;
      int iSection = 3;
      int iKey = 4;
      int iValue = 5;
      if (cArg < 5) usage();
      if (strcmp(aszArg[1], "get") != 0 && strcmp(aszArg[1], "set") != 0) usage();
      if (strcmp(aszArg[1], "set") == 0 && cArg < iValue + 1) usage();
      if (strcmp(aszArg[1], "set") == 0) {
        if (!WritePrivateProfileString(aszArg[iSection], aszArg[iKey],
                                       aszArg[iValue], aszArg[iFile]))
          puts("Failure in WriteProfileString.");
      } else {
        char buf[1000];
        buf[0] = 0;
        GetPrivateProfileString(
          aszArg[iSection], aszArg[iKey], "", buf, 999, aszArg[iFile]);
        puts(buf);
      }
      return 0;
    }
    

    您需要使用适用于 Windows 的 c 编译器对其进行编译。我用 gcc 做的,但是 ms 的免费编译器也应该可以工作。如果带有 32 位可执行文件的 this page 仍然可用,您可以尝试一下,但需要您自己负责。黑客已经访问过我的网站一次。

    【讨论】:

      【解决方案2】:

      我编写了一个小的 VBScript 类来处理以这种格式编写的“真实”ini 文件:

      [section_name] 键 1 = 值 1 键2 = 值2

      类的代码是:

      Class IniFileObject
          Private m_Data
      
          Private Sub Class_Initialize
              Set m_Data = Server.CreateObject("Scripting.Dictionary")
          End Sub
      
          Private Sub Class_Terminate
              Dim key
              If IsObject(m_Data) Then
                  For Each key In m_Data
                      m_Data(key).RemoveAll
                      Set m_Data(key) = Nothing
                  Next
                  m_Data.RemoveAll
                  Set m_Data = Nothing
              End If
          End Sub
      
          Public Function Init(sFilePath)
              Dim arrLines, sLine, x
              Dim sCurSection, oSectionDict
              Set Init = Me
              arrLines = GetFileLines(sFilePath)
              If Not(IsArray(arrLines)) Then Exit Function
              sCurSection = ""
              For x = 0 To UBound(arrLines)
                  sLine = Trim(arrLines(x))
                  If Len(sLine)>0 Then
                      If Left(sLine, 1)="[" Then
                          If Not(HandleSectionLine(sLine, sCurSection)) Then Exit Function
                      Else  
                          If Len(sCurSection)=0 Then
                              Err.Raise 1005, "IniFileObject init", "Found value outside any section (" & Server.HTMLEncode(sLine) & ")"
                              Exit Function
                          End If
      
                          Set oSectionDict = m_Data(sCurSection)
                          If Not(ParseOneLine(sLine, oSectionDict)) Then Exit Function
                          Set m_Data(sCurSection) = oSectionDict
                      End If
                  End If
              Next
          End Function
      
          Public Property Get ReadValue(section, key)
              Dim oSectionDict
              ReadValue = ""
              If m_Data.Exists(section) Then
                  Set oSectionDict = m_Data(section)
                  If oSectionDict.Exists(key) Then ReadValue = oSectionDict(key)
              End If
          End Property
      
          Private Function ParseOneLine(ByVal sLine, ByRef oSectionDict)
              Dim arrTemp, sErrorMsg, sKey
              sErrorMsg = ""
              ParseOneLine = True
              If Left(sLine, 2)="//" Or Left(sLine, 1)="'" Or Left(sLine, 1)="{" Then Exit Function
              arrTemp = Split(sLine, "=")
              If UBound(arrTemp)=1 Then
                  sKey = Trim(arrTemp(0))
                  If (Len(sKey)>0) And (Len(arrTemp(1))>0) Then
                      If Not(oSectionDict.Exists(sKey)) Then
                          oSectionDict.Add sKey, Trim(arrTemp(1))
                      Else  
                          sErrorMsg = "Key already exists"
                      End If
                  Else  
                      sErrorMsg = "Empty key or value"
                  End If
              Else  
                  sErrorMsg = "Missing or too much '=' characters"
              End If
              Erase arrTemp
              If Len(sErrorMsg)>0 Then
                  ParseOneLine = False
                  Err.Raise 1006, "IniFileObject Init", "Failed to parse single line (" & Server.HTMLEncode(sLine) & "): " & sErrorMsg
              End If
          End Function
      
          Private Function HandleSectionLine(ByVal sLine, ByRef sCurSection)
              HandleSectionLine = False
              If (Len(sLine)<3) Or (Right(sLine, 1)<>"]") Then
                  Err.Raise 1002, "IniFileObject init", "Invalid line found: " & Server.HTMLEncode(sLine)
                  Exit Function
              End If
      
              sCurSection = Mid(sLine, 2, Len(sLine) - 2)
              If m_Data.Exists(sCurSection) Then
                  Err.Raise 1003, "IniFileObject init", "Section exists more than once: " & Server.HTMLEncode(sCurSection)
                  Exit Function
              End If
      
              m_Data.Add sCurSection, Server.CreateObject("Scripting.Dictionary")
              HandleSectionLine = True
          End Function
      
          Private Function GetFileLines(sFilePath)
              Dim objFSO, oFile
              Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
              If Not(objFSO.FileExists(sFilePath)) Then
                  Set objFSO = Nothing
                  Err.Raise 1001, "IniFileObject init", "file path '" & Server.HTMLEncode(sFilePath) & "' does not exist, check permissions"
                  Exit Function
              End If
              Set oFile = objFSO.OpenTextFile(sFilePath)
              GetFileLines = Split(oFile.ReadAll, VBCrLf)
              oFile.Close
              Set oFile = Nothing
              Set objFSO = Nothing
          End Function
      End Class
      

      使用示例:

      Dim filePath, ini
      filePath = Server.MapPath("config.ini")
      Set ini = New IniFileObject.Init(filePath)
      Response.Write("Value for 'Key001': " & ini.ReadValue("MySection", "Key001") & "<br />")
      Set ini = Nothing
      

      当文件不存在或包含无效行时,代码会抛出各种错误,错误非常清楚。在消费时使用这样的代码可以“抑制”错误并且不显示错误页面:

      On Error Resume Next
          Set ini = New IniFileObject.Init(filePath)
          If Err.Number<>0 Then
              Response.Write("Error reading ini file")
          End If
      On Error Goto 0
      If IsObject(ini) Then
          Response.Write("Value for 'IP001': " & ini.ReadValue("IPaddress", "IP001") & "<br />")
          Set ini = Nothing
      End If
      

      【讨论】:

        【解决方案3】:

        我可能会改用 CSV 文件,其中每一行代表一个国家/地区。

        Country,Address1,Address2,Address3,Address4
        London,Address 1,Postbox 3245,58348 London
        Copenhagen,Address 2,Postbox 2455,5478347,Copenhagen
        

        如果您可以轻松识别您的数据,那么您可能会有更具描述性的列名(即 Street1、Street2、Town、Postcode 等)。

        这种文件格式也很容易阅读,因为您一次只读取输入文件的一行并使用类似的方式将其拆分

        aAddress = split(sLine, ",")
        

        为了更容易使用,您可以使用字典对象并将国家/地区用作键和数组作为值

        'sLine should be read from input file'
        sLine = "Copenhagen,Address 2,Postbox 2455,5478347,Copenhagen"
        
        'Create dictionary for addresses'
        Set dic = CreateObject("Scripting.Dictionary")
        
        'Split line into array'
        aAddressParts = Split(sLine, ",") 
        
        'Remove the first element of the array'
        sValues = Mid(sLine, InStr(sLine, ",")+1)
        aValues = Split(sValues, ",")
        
        'Add new entry into dictionary'
        dic.Add aAddressParts(0), aValues
        
        'Usage'
        MsgBox "Address for Copenhagen: " & vbNewLine & _
            Join(dic("Copenhagen"), "," & vbNewLine)
        

        谢谢, 马切耶

        【讨论】:

        • 好主意 :) 关于这一切的全部想法是客户端必须能够以可读的格式轻松编辑数据。 CSV 可以用 Excel 打开。很棒的提示! :)
        【解决方案4】:

        您可以将地址存储在一行中并使用特殊字符(例如下划线)来表示换行符。读取地址时,只需将特殊字符替换为换行即可。

        [伦敦]
        地址 = "邮箱 3245_58348 伦敦”

        [哥本哈根]
        地址 = "邮箱 2455_5478347 哥本哈根"

        这也允许您存储包含更多行或不包含邮箱行的地址。根据我的经验,“我们的地址总是正好有两行,第一行是总是邮箱”这样的信息经常是不正确的。 .

        【讨论】:

        • 试试Replace(ReadIni, "_", vbCrLf),不要在vbCrLf周围加引号。
        猜你喜欢
        • 2013-09-13
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-13
        • 2012-03-29
        相关资源
        最近更新 更多