问题
I want to store some addresses in a text file and then read specific portions of the file, based on group membership. I've done all of the group membership stuff so I don't need any help for that.
But I'm not sure if I should use a plain text file or an INI file?
The thing is, the post addresses are in two or three lines and I need line break.
I tried using a plain text file, but I couldn't manage to get a line break correctly.
So INI files would be preferable?
The INI file could look like this:
[London] Address 1 Postbox 3245 58348 London [Copenhagen] Address 2 Postbox 2455 5478347 Copenhagen
I'm not quite sure if this is possible in an INI file though, perhaps I need to name each line as well. OR, I could possibly use a plain text file and search for the word [london] and then read each line until there's a line break. Then store all of those lines in a variable that I'll pass along?
How would you guys solve this?
回答1:
I would probably use CSV file instead where each row will represent a country.
Country,Address1,Address2,Address3,Address4
London,Address 1,Postbox 3245,58348 London
Copenhagen,Address 2,Postbox 2455,5478347,Copenhagen
If you can easily identify your data then you could probably have more descriptive column names (i.e. Street1, Street2, Town, Postcode, etc.).
This file format is also easy to read since you only read one line of the input file at a time and split it using something like
aAddress = split(sLine, ",")
To make it even easier to work with you could use dictionary object and use country as a key and array as a value
'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)
Thanks, Maciej
回答2:
I have written a small VBScript Class that handles "real' ini files written with such format:
[section_name] key1 = value1 key2 = value2
The code for the class is:
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
Usage example:
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
The code throw various errors when the file does not exist or contains invalid lines, the errors are pretty much clear. It's possible to "suppress" the errors and not display error page by using such code when consuming:
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:
You could store the addresses in one line and use a special character, for example an underscore, to indicate a line break. When you read the address, you just need to replace the special character with a line break.
[London]
Address = "Postbox 3245_58348 London"[Copenhagen]
Address = "Postbox 2455_5478347 Copenhagen"
That allows you to store addresses with more lines or without a postbox line, as well. In my experience, information like "our addresses always have exactly two lines and the first one is always a postbox" is very often incorrect...
回答4:
I use a small executable that launches native api for that: GetPrivateProfileString and WritePrivateProfileString.
The executable is called like that:
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)
See also Running command line silently with VbScript and getting output?.
This is the code of the executable:
#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;
}
You need to compile it using a c compiler for Windows. I did it with gcc, but a free compiler from ms should also work. If this page with a 32-bit executable is still available, you may give it a try, but on your own responsibility. Hackers already visited my site once.
来源:https://stackoverflow.com/questions/3491965/vbscript-read-ini-or-text-file-for-specific-section