Click here to Skip to main content
15,883,817 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
I was wondering if anyone had any ideas on how to remove a Key in an INI file when it's empty? I found the code for Read/Write to an INI file a while back and if I recall correctly I just made a simple change for my own use. However, changing it to remove an empty Key seems to be avoiding me. It's not really a big deal but I would like to keep my INI file clean whenever possible.

I can't recall where I got the code for the INI {read & write} but here is the Write portion - where I'd like the Removal code to be:

VB
Option Strict Off
Option Explicit On
Module INIwrite
    '       xxx = ReadINI("FILE", "SECTION", "KEY")
    '       WriteINI("FILE", "SECTION", "KEY", "VALUE")

    Public Function WriteIni(ByRef INIpath As String, ByRef PutKey As String, ByRef PutVariable As String, ByRef PutValue As String) As Object
        Dim Temp As String
        Dim LcaseTemp As String
        Dim ReadKey As String
        Dim ReadVariable As String
        Dim LOKEY As Short
        Dim HIKEY As Short
        Dim KEYLEN As Short
        Dim VAR As Short
        Dim VARENDOFLINE As Short
        Dim NF As Short

AssignVariables:
        NF = FreeFile()
        ReadKey = vbCrLf & "[" & LCase(PutKey) & "]" & Chr(13)
        KEYLEN = Len(ReadKey)
        ReadVariable = Chr(10) & LCase(PutVariable) & "="

EnsureFileExists:
        FileOpen(NF, INIpath, OpenMode.Binary)
        FileClose(NF)
        SetAttr(INIpath, FileAttribute.Archive)

LoadFile:
        FileOpen(NF, INIpath, OpenMode.Input)
        Temp = InputString(NF, LOF(NF))
        Temp = vbCrLf & Temp & "[]"
        FileClose(NF)
        LcaseTemp = LCase(Temp)

LogicMenu:
        LOKEY = InStr(LcaseTemp, ReadKey)
        If LOKEY = 0 Then GoTo AddKey
        HIKEY = InStr(LOKEY + KEYLEN, LcaseTemp, "[")
        VAR = InStr(LOKEY, LcaseTemp, ReadVariable)
        If VAR > HIKEY Or VAR < LOKEY Then GoTo AddVariable
        GoTo RenewVariable

AddKey:
        Temp = Left(Temp, Len(Temp) - 2)
        Temp = Temp & vbCrLf & vbCrLf & "[" & PutKey & "]" & vbCrLf & PutVariable & "=" & PutValue
        GoTo TrimFinalString

AddVariable:
        Temp = Left(Temp, Len(Temp) - 2)
        Temp = Left(Temp, LOKEY + KEYLEN) & PutVariable & "=" & PutValue & vbCrLf & Mid(Temp, LOKEY + KEYLEN + 1)
        GoTo TrimFinalString

RenewVariable:
        Temp = Left(Temp, Len(Temp) - 2)
        VARENDOFLINE = InStr(VAR, Temp, Chr(13))
        Temp = Left(Temp, VAR) & PutVariable & "=" & PutValue & Mid(Temp, VARENDOFLINE)
        GoTo TrimFinalString

TrimFinalString:
        Temp = Mid(Temp, 2)
        Do Until InStr(Temp, vbCrLf & vbCrLf & vbCrLf) = 0
            Temp = Replace(Temp, vbCrLf & vbCrLf & vbCrLf, vbCrLf & vbCrLf)
        Loop

        Do Until Right(Temp, 1) > Chr(13)
            Temp = Left(Temp, Len(Temp) - 1)
        Loop

        Do Until Left(Temp, 1) > Chr(13)
            Temp = Mid(Temp, 2)
        Loop

OutputAmendedINIFile:
        FileOpen(NF, INIpath, OpenMode.Output)
        PrintLine(NF, Temp)
        FileClose(NF)

    End Function
End Module


I'd like to have it so it just needs empty quotes where the value would be to remove an entry. Example:
VB
WriteINI(flIni, "NxtMo", "GstBnk" & i, "")


Thanks for any help you can provide!!

Peace to you and yours,
Matthew "Dra'Gon" Stohler
Posted
Updated 31-Dec-17 4:19am
v2
Comments
Bruce Munck 31-Dec-17 10:16am    
If you are looking for the easiest way to delete items fron an INI file, try using the API like this: n = WritePrivateProfileString("", "<key>", 0&, "<inipath>"). This will delete a single key and its value.

To delete an entire section, use this: n = WritePrivateProfileString("", 0&, "<value>", "<inipath>"). The following will do the same thing n = WritePrivateProfileString("", 0&, 0&, "<inipath>"). Use of either construct is correct, so choose the one you like best.

To add to an INI file: n = WritePrivateProfileString("", "<key>", "<value>", "<inipath>").

As for the WriteIni function in this article, I am not the author. I also ran into it while searching for ini file solutions several years ago and have been using it as written without any problems since around 2008. The only thing this code does that using the API "WritePrivateProfileString" does not do is to put a blank line between sections. So, on the one hand, if you don't need or care about blank lines making the file more readable, you really don't need to use this code since the API will do all the other formatting for you with a one-line call. On the other hand, if you like the idea of blank lines between sections, then this piece of code is an easy way of having them inserted properly. I have no idea why the author chose to make it a function, but it isn't a big chore to change it to a SUB. As for the GOTO's, I recently re-wrote this routine as a SUB and wrote all of the GOTO targets as separate SUB's and changed the GOTO's to standard calls. I think the original, with the GOTO's, looks neater than the re-written code. I am also of the opinion that the GOTO's were done properly and don't hurt anything. Having said that, I now use, and will continue to use, my re-written version of the above code, sans GOTO's, as it is more acceptable.
Bruce Munck 31-Dec-17 10:22am    
In my comment and solution I left closed quotes where there should have been the following: "". Sorry.
Bruce Munck 31-Dec-17 10:27am    
Ok, I guess my entries are being changed. Let's try this: n = WritePrivateProfileString(, <key>, <value>, <inipath>). should appear in all the calls.
Bruce Munck 31-Dec-17 10:31am    
Well, here goes. The leading quotes are supposed to contain the name of the section enclosed in "[]". For some reason that is being deleted. If this doesn't work I guess I'll give up.

I think you have more problems than just that...but to solve that one add this to the beginning:
VB
If (String.IsNullOrEmpty(PutValue)) Then
    Return
End If


Next, why is your function of object type if you don't return anything? Change the declaration to
VB
Public Sub WriteIni(ByRef INIpath As String, ByRef PutKey As String, ByRef PutVariable As String, ByRef PutValue As String)


Also, if you intend to write multiple values, you should really only open and close the file once, maybe outside where you are calling this function, and pass it the file's output stream instead. (Google can help you there).

And I'm not even going to go into the usage of goto's...


And here's a short program to remove existing empty entries:
VB
Imports System.Linq
Imports System.IO
Imports System.Text.RegularExpressions

Namespace RemoveEmptyValues
	Class Program
		Private Shared Sub Main(arguments As String())
			Dim filePath As String = "path\to\file"

			File.WriteAllLines(filePath, File.ReadAllLines(filePath).Where(Function(x) Not Regex.IsMatch(x, ".+=$")).ToArray())
		End Sub
	End Class
End Namespace
 
Share this answer
 
v2
Comments
BlueDragonFire 24-Jul-12 12:02pm    
Yah, I didn't actually write the code. I found it online but I can't seem to find it again to ask the Originator. The "Goto" statements were already there. I didn't know about that "As Object" deal so I'll give it a shot without that.

I totally agree on opening it once for multiple entries but I'm still very much a beginner at coding and didn't want to risk screwing the Read/Write INI modules up when they're so useful. D@mn Microsoft anyway for removing that functionality ;). I really don't like the look/feel of XML files for some reason.

I don't see how your "If" statement would remove the empty Key though. As it is, when I clear a Key the INI file still has that Key listed - Example:
[NxtMo]
nGuests=0
GstBnk1=
AbsRsn1=
AbsStrt1=
AbsDays1=

What I want is for those empty entries to be completely removed from the INI file. Otherwise it just looks sloppy to me. That "nGuests" holds the number of items so it needs to remain. But the items could be any number and to have a dozen or so empty Keys is just annoying IMO.

Thanks for your help!

Peace to you and yours,
Matthew "Dra'Gon" Stohler
lewax00 24-Jul-12 12:36pm    
Well what it really does is prevent them from being written in the first place. You'll have to rewrite the file for them all to be removed. I assumed since it looks like it's appending changes that the file would be rewritten each time, but maybe I assumed incorrectly, if I did let me know, writing something to go through once and remove them isn't complicated, and I can add it to the solution.
BlueDragonFire 24-Jul-12 14:38pm    
What my program does in this part is it takes the user-input information and uses the WriteINI to store it in those Key-sets for later, updating the counter "nGuests" per set.

When the program is started for the first time in a new month it looks to see if "nGuests" is > 0 {using ReadINI}. If so then it does a loop of that number and retrieves the info from the 4 entries of each set to put on the monthly Excel form I made specifically for this program. Then it removes those entries from the INI file, leaving the Keys blank.

I just figured since the WriteINI is able to find each Key and make it blank {from "GstBnk1=21" to "GstBnk1=" for instance} that it should also be able to just remove that line altogether. But what you said about having to rewrite the file for that makes sense.

Maybe if I use your "If" statement, but instead of the "Return" I make it so it reads the INI file {which shouldn't get too large at all} into a variable, deletes the INI, then removes the line(s) from that variable and writes the variable into a new INI of the same name.

If you, or someone else {including myself}, doesn't come up with a less intrusive method then it looks like this will be my best option. Probably would be better to add it as a separate module to be accessed after the Key(s) is/are made blank.

Thanks for your help! It got my mind working in a useable direction anyway. :D

Peace to you and yours,
Matthew "Dra'Gon" Stohler

P.S. I'm going to "Accept" this solution but if anyone reading this has an alternative that will work please post it! Thanks!!
lewax00 24-Jul-12 15:04pm    
Well I added the code for a program that you can run once to remove existing missing entries, that with the modification I mentioned should solve your problem (the program should remove any that exist, and the modification should prevent new ones from being added).
BlueDragonFire 24-Jul-12 15:22pm    
I'm not even going to pretend to understand what all that is doing! LOL!!
I'll certainly give it a shot though. THANKS!
This will delete a single key and its value.
n = WritePrivateProfileString("
", "<key>", 0&, "<inipath>").

To delete an entire section, use this: n = WritePrivateProfileString("
", 0&, "<value>", "<inipath>" or this: n = WritePrivateProfileString("
", 0&, 0&, "<inipath>"). Use of either construct is correct, so choose the one you like best.

To add to an INI file: n = WritePrivateProfileString("
", "<key>", "<value>", "<inipath>").
 
Share this answer
 
Comments
Richard MacCutchan 31-Dec-17 10:34am    
Only FIVE+ years too late.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900