views:

983

answers:

4

How do you write or read to external files with custom extensions (like, instead of a .txt extension it could have .cyc for example) using VBscript?

I don't know how, and cannot seem to figure it out. For reading a file, is it possible to only read part of a file? For example, if I have a line

string1=Hello World!

inside of my file, how does my script only read from the string1 line and how can it assign the text value to a string in the vbscript file?

Then, how can I write a single value to my file?

To clarify, I am basically attempting to use external files as configuration/data files.

This is probably a really nooby question, and I am really sorry if it is.

EDIT: This is a two part question, I need to know the code to read and write files as specified above, and how to use custom extensions with it.

+1  A: 

All you should have to do is include the extension on the end of the filename, like this:

c:\myfolder\myfile.ext

when you open the file for writing.

Here is some sample code that opens a new file, writes a line of text to it, and closes the file:

Set myFSO = CreateObject("Scripting.FileSystemObject")
Set WriteStuff = myFSO.OpenTextFile("c:\myfolder\myfile.ext", 2, true)
WriteStuff.WriteLine("Hello World.")
WriteStuff.Close
Set WriteStuff = nothing
Set myFSO = nothing

Here is the code to read it back:

Dim S as String
Set myFSO = CreateObject("Scripting.FileSystemObject")
Set ReadStuff = myFSO.OpenTextFile("c:\myfolder\myfile.ext", 1)
S=Readstuff.ReadLine
ReadStuff.Close
Set ReadStuff = nothing
Set myFSO = nothing

There are some more examples at http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/other/textfiles/

Robert Harvey
But how do I open the file for writing in the first place? This is really a two-part question.
Cyclone
Okay, thank you for the code. Can you explain what the params do? What do the 2 and True do?
Cyclone
The 2 means open a new file for writing. I'm not sure what the true is for, but it is in Microsoft's examples.
Robert Harvey
Okay. How do I choose what line number it reads from?
Cyclone
It reads from the first line, and reads from the next line if you execute Readline again, and so on. See http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/other/textfiles/ for more examples.
Robert Harvey
Alright, but is there any way to have it read from a specific line number, like, the third one down or something? Same with writing.
Cyclone
The parameters of the OpenTextFile method are File(the file to be opened), IOMode(1=ForReading 2=ForWriting 8=ForAppending), Create(True= create the file if it does not exist. False= Do not create the file.)
Tester101
+1  A: 

If you want to read and write from the text file at random locations, your best bet is to use INI files.

An INI file contains entries that look like this:

[owner]
name=John Doe
organization=Acme Products

To read an ini file, you need a function that you can call like this:

Dim s as string
s=ReadINI("c:\myfolder\myfile.ext", "owner", "name")

...which will put "John Doe" in s.

The code to do this is here: http://cwashington.netreach.net/depo/view.asp?Index=553

Writing the INI file works the same way.

Here is another example:

WriteINI("c:\myfolder\myfile.ext", "MySection", "MyItem", "MyValue")

creates an INI file that looks like this:

[MySection]
MyItem=MyValue

You can have as many different sections and items within each section as you want. All you have to do to retrieve the value that you want is to call ReadINI with the section name and item name of the value you want to retrieve.

Robert Harvey
That sounds like what I am looking for, but is there any way to get similar functionality out of a different extension?
Cyclone
Extension? The .EXT can be anything you want. The string in [owner] can be anything you want. Name and Organization are things you decide, as are the the values.
Robert Harvey
Okay, so I can use whatever extension I want but have it treated as an INI file? Thanks! This solves my problem, and I am assuming that WriteINI is the write function?What does [owner] declare, and how do I show that it has reached the end of this declaration and has moved on to the next?
Cyclone
See my edits above.
Robert Harvey
Just call WriteINI for each item and value that you want to declare. It doesn't matter in what order you write the values.
Robert Harvey
Okay, thanks. Is there a way to declare the end of a section or does it terminate by itself when the next section is declared?
Cyclone
It places your items into whatever section you specify. No termination required.
Robert Harvey
If the section does not exist yet, it will create it as needed.
Robert Harvey
But if I manually create a section, how does it know where the section ends?Also, how do I make it create a new file, one that did not previously exist?
Cyclone
The beauty of WriteINI is you shouldn't have to think about any of these things. If the file doesn't exist, WriteINI will create it. The section ends when another section head begins, or end of file is encountered. But you don't need to worry about this either. What you DO need to know are the names of your items, because you do have to read them individually with this method. If you are numbering your items and you don't know how many there are, put in an item that has the count (number of items).
Robert Harvey
Very cool, thanks so much! Last question: when files are written or read, what is the standard location that data is stored in? Also, is it possible to use relative locations? Thanks!
Cyclone
Umm, if I were to pick a standard folder location, I guess it would be c:\documents and settings\{User Name}\application data\my application. Sure it is possible to use relative locations. The path I just described is in the %APPDATA% environment variable, so the relative folder path is %APPDATA%\MyApplication.
Robert Harvey
Ah, okay. Er, I tried using WriteINI and ReadINI but it said the name was not declared. I am running VB 2008 Express edition with SP1. Is there something I need to declare first?
Cyclone
Oh, and in fact, creating a new FSO fails as well, it gives me syntax errors. Do I declare my FileSystemObject in public declarations or in a private sub?
Cyclone
The ReadINI and WriteINI code is here: http://cwashington.netreach.net/depo/view.asp?Index=553. You need to include that code in your script for this to work.
Robert Harvey
Oh, I see. I thought the ReadINI and WriteINI methods were built into VB. Thanks!
Cyclone
Wait, it is generating tons of syntax errors. This code goes where in my script exactly? I tried public declarations, a private sub, below the subs, etc. It seems as though it is missing all its Dim statements?
Cyclone
Cyclone, see my new posting. It is similar code but from a different source. I tested it, and it actually works. Imagine that. At the bottom of the script I have posted are the lines that actually call the WriteINI sub to write the values into the INI file. Let me know how it goes.
Robert Harvey
A: 

Cyclone:

  1. Create the folder c:\testarea.
  2. Create a text file called test.vbs in the folder you just created, and paste the code below into it.
  3. Double-click the test.vbs file to execute it. Notice that it creates a test.ini file in the same directory. Open test.ini and view it.

This code has been tested, so I know it works. I got it from http://www.robvanderwoude.com/vbstech_files_ini.php

      Function ReadIni( myFilePath, mySection, myKey )
 ' This function returns a value read from an INI file
 '
 ' Arguments:
 ' myFilePath  [string]  the (path and) file name of the INI file
 ' mySection   [string]  the section in the INI file to be searched
 ' myKey       [string]  the key whose value is to be returned
 '
 ' Returns:
 ' the [string] value for the specified key in the specified section
 '
 ' CAVEAT:     Will return a space if key exists but value is blank
 '
 ' Written by Keith Lacelle
 ' Modified by Denis St-Pierre and Rob van der Woude

 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
    End Function


    Sub WriteIni( myFilePath, mySection, myKey, myValue )
 ' This subroutine writes a value to an INI file
 '
 ' Arguments:
 ' myFilePath  [string]  the (path and) file name of the INI file
 ' mySection   [string]  the section in the INI file to be searched
 ' myKey       [string]  the key whose value is to be written
 ' myValue     [string]  the value to be written (myKey will be
 '                       deleted if myValue is <DELETE_THIS_VALUE>)
 '
 ' Returns:
 ' N/A
 '
 ' CAVEAT:     WriteIni function needs ReadIni function to run
 '
 ' Written by Keith Lacelle
 ' Modified by Denis St-Pierre, Johan Pol and Rob van der Woude

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

 Dim blnInSection, blnKeyExists, blnSectionExists, blnWritten
 Dim intEqualPos
 Dim objFSO, objNewIni, objOrgIni, wshShell
 Dim strFilePath, strFolderPath, strKey, strLeftString
 Dim strLine, strSection, strTempDir, strTempFile, strValue

 strFilePath = Trim( myFilePath )
 strSection  = Trim( mySection )
 strKey      = Trim( myKey )
 strValue    = Trim( myValue )

 Set objFSO   = CreateObject( "Scripting.FileSystemObject" )
 Set wshShell = CreateObject( "WScript.Shell" )

 strTempDir  = wshShell.ExpandEnvironmentStrings( "%TEMP%" )
 strTempFile = objFSO.BuildPath( strTempDir, objFSO.GetTempName )

 Set objOrgIni = objFSO.OpenTextFile( strFilePath, ForReading, True )
 Set objNewIni = objFSO.CreateTextFile( strTempFile, False, False )

 blnInSection     = False
 blnSectionExists = False
 ' Check if the specified key already exists
 blnKeyExists     = ( ReadIni( strFilePath, strSection, strKey ) <> "" )
 blnWritten       = False

 ' Check if path to INI file exists, quit if not
 strFolderPath = Mid( strFilePath, 1, InStrRev( strFilePath, "\" ) )
 If Not objFSO.FolderExists ( strFolderPath ) Then
  WScript.Echo "Error: WriteIni failed, folder path (" _
       & strFolderPath & ") to ini file " _
       & strFilePath & " not found!"
  Set objOrgIni = Nothing
  Set objNewIni = Nothing
  Set objFSO    = Nothing
  WScript.Quit 1
 End If

 While objOrgIni.AtEndOfStream = False
  strLine = Trim( objOrgIni.ReadLine )
  If blnWritten = False Then
   If LCase( strLine ) = "[" & LCase( strSection ) & "]" Then
    blnSectionExists = True
    blnInSection = True
   ElseIf InStr( strLine, "[" ) = 1 Then
    blnInSection = False
   End If
  End If

  If blnInSection Then
   If blnKeyExists Then
    intEqualPos = InStr( 1, strLine, "=", vbTextCompare )
    If intEqualPos > 0 Then
     strLeftString = Trim( Left( strLine, intEqualPos - 1 ) )
     If LCase( strLeftString ) = LCase( strKey ) Then
      ' Only write the key if the value isn't empty
      ' Modification by Johan Pol
      If strValue <> "<DELETE_THIS_VALUE>" Then
       objNewIni.WriteLine strKey & "=" & strValue
      End If
      blnWritten   = True
      blnInSection = False
     End If
    End If
    If Not blnWritten Then
     objNewIni.WriteLine strLine
    End If
   Else
    objNewIni.WriteLine strLine
     ' Only write the key if the value isn't empty
     ' Modification by Johan Pol
     If strValue <> "<DELETE_THIS_VALUE>" Then
      objNewIni.WriteLine strKey & "=" & strValue
     End If
    blnWritten   = True
    blnInSection = False
   End If
  Else
   objNewIni.WriteLine strLine
  End If
 Wend

 If blnSectionExists = False Then ' section doesn't exist
  objNewIni.WriteLine
  objNewIni.WriteLine "[" & strSection & "]"
   ' Only write the key if the value isn't empty
   ' Modification by Johan Pol
   If strValue <> "<DELETE_THIS_VALUE>" Then
    objNewIni.WriteLine strKey & "=" & strValue
   End If
 End If

 objOrgIni.Close
 objNewIni.Close

 ' Delete old INI file
 objFSO.DeleteFile strFilePath, True
 ' Rename new INI file
 objFSO.MoveFile strTempFile, strFilePath

 Set objOrgIni = Nothing
 Set objNewIni = Nothing
 Set objFSO    = Nothing
 Set wshShell  = Nothing
    End Sub
         '
         '
    Call  WriteINI("c:\testarea\Test.INI","Section1","Item1","Value1")
    Call  WriteINI("c:\testarea\Test.INI","Section1","Item2","Value2")
    Call  WriteINI("c:\testarea\Test.INI","Section1","Item3","Value3")
    Call  WriteINI("c:\testarea\Test.INI","Section2","Item4","Value4")
    Call  WriteINI("c:\testarea\Test.INI","Section2","Item5","Value5")
Robert Harvey
So how do I then utilize this code inside of my application?
Cyclone
Ah, an application. What does your application look like? Is it truly being written totally in vbscript? Because if it isn't there are potentially better ways to do this.
Robert Harvey
Its a "Windows form application", its being written mostly in vbscript but designed with the visual editor.I dont know enough vbscript to do it entirely by hand.
Cyclone
If you don't mind me asking, why are you attempting to write such an application in vbscript? Why don't you write it in VB.NET? Even vb6 would be better for a forms application. The code for your INI files would be almost trivial in these two environments.
Robert Harvey
I have vb 2008 express, can I make .net stuff with it? If so, how? Thanks for all the help with this btw, I really appreciate it.
Cyclone
Now you're catching on. Create a Winforms application in vb2008 express. There should be some tutorials that come with vb2008 express if you get stuck. I will post the INI code for vb.net shortly.
Robert Harvey
+1  A: 

The following class reads and writes INI files from VB.Net:

Class INI

#Region "API Calls"
 ' standard API declarations for INI access
 ' changing only "As Long" to "As Int32" (As Integer would work also)
 Private Declare Unicode Function WritePrivateProfileString Lib "kernel32" _
 Alias "WritePrivateProfileStringW" (ByVal lpApplicationName As String, _
 ByVal lpKeyName As String, ByVal lpString As String, _
 ByVal lpFileName As String) As Int32

 Private Declare Unicode Function GetPrivateProfileString Lib "kernel32" _
 Alias "GetPrivateProfileStringW" (ByVal lpApplicationName As String, _
 ByVal lpKeyName As String, ByVal lpDefault As String, _
 ByVal lpReturnedString As String, ByVal nSize As Int32, _
 ByVal lpFileName As String) As Int32
#End Region

 Public Overloads Function INIRead(ByVal INIPath As String, _
 ByVal SectionName As String, ByVal KeyName As String, _
 ByVal DefaultValue As String) As String
  ' primary version of call gets single value given all parameters
  Dim n As Int32
  Dim sData As String
  sData = space$(1024) ' allocate some room 
  n = GetPrivateProfileString(SectionName, KeyName, DefaultValue, _
  sData, sData.Length, INIPath)
  If n > 0 Then ' return whatever it gave us
   INIRead = sdata.Substring(0, n)
  Else
   iniread = ""
  End If
 End Function

#Region "INIRead Overloads"
 Public Overloads Function INIRead(ByVal INIPath As String, _
 ByVal SectionName As String, ByVal KeyName As String) As String
  ' overload 1 assumes zero-length default
  Return INIRead(inipath, sectionname, KeyName, "")
 End Function

 Public Overloads Function INIRead(ByVal INIPath As String, _
 ByVal SectionName As String) As String
  ' overload 2 returns all keys in a given section of the given file
  Return INIRead(inipath, sectionname, Nothing, "")
 End Function

 Public Overloads Function INIRead(ByVal INIPath As String) As String
  ' overload 3 returns all section names given just path
  Return INIRead(inipath, Nothing, Nothing, "")
 End Function
#End Region

 Public Sub INIWrite(ByVal INIPath As String, ByVal SectionName As String, _
 ByVal KeyName As String, ByVal TheValue As String)
  Call WritePrivateProfileString(SectionName, KeyName, TheValue, INIPath)
 End Sub

 Public Overloads Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String, _
 ByVal KeyName As String) ' delete single line from section
  Call WritePrivateProfileString(SectionName, KeyName, Nothing, INIPath)
 End Sub

 Public Overloads Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String)
  ' delete section from INI file
  Call WritePrivateProfileString(SectionName, Nothing, Nothing, INIPath)
 End Sub

End Class
Robert Harvey
Okay so wait, to utilize vb.net in vb 2008express, all I have to do is change my syntax usage?Cool!
Cyclone
Er, do you have any good tutorials for vb.net stuff?
Cyclone
This link: http://stackoverflow.com/questions/71956/vb-net-tutorials should get you started.
Robert Harvey
Thanks much. You have been a big help :D
Cyclone