Tech Note 08: File Control
This control is used to read and write files. It is included with NS Basic. The information in the document is for the most part copied from the official documentation on NewObject's website. For further information, please refer to the official documentation. The information on this page is copyright ZmeY soft and published with their permission.
Background: This control replaces the MSCEFile control in NS Basic/CE and the FileSystemObject (FSO) in NS Basic/Desktop. Code written using this control is interoperable between both NS Basic products.
The File I/O Control is used to read and write data in files. It is useful for files where entire records are read or written in string or binary format. If you would like to read and write your records as separate fields, have a look at Tech Note 8a "File I/O with Fields".
The methods and properties documented here are a subset of the full capabilities of this control. To see the rest of the features, look at the full documentation from NewObjects. The features not included here will still work well with NS Basic, but are for advanced users.
Comma separated files (csv) can be easily handled by this control. Use the ReadText function to read in the entire record, then do a Split(record, ",") function to break it into its array of variables.
Before any of the items below can be used, the file needs to be opened. Do this using the OpenFile method in the File System Control.
Installation: This control requires that NewObjectsPack1.dll be installed and registered.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt")
|Size||Size of the file|
|Pos||Position in the file (in bytes)|
|textLineSeparator||Text line separator (defaults to the windows standard)|
|unicodeText||Text access as UNICODE (True) or ANSI (False). Default is ANSI|
|codePage||If unicodeText is False this specifies the code page used for text conversion.|
|EOS||Becomes True if the end of file is reached|
|maxTextBuff||Maximum buffer size for the text lines.|
|stats||Gets the file information (name, size, times etc.)|
|ReadBin||Reads binary data and returns it as array of bytes packed in a variant.|
|WriteBin||Writes binary data|
|Seek||Changes/obtains the current position in the File.|
|CopyTo||Copies from this file to another.|
|ReadText||Reads text from the file (line, specified number of characters or the entire file)|
|WriteText||Writes text to the File.|
|Close||Releases/closes the File.|
|Find||Binary search through the file beginning from the current position.|
Returns the size of the file or resizes it. The size is in bytes.
variable = File.Size
File.Size = newSize
When read the property returns the total size of the file in bytes. Writing the property allows the application to truncate or enlarge the File.
Gets/sets the absolute position of the File.
variable = File.Pos
File.Pos = variable
Position 1 or more: the byte index in the File.
If positioned beyond the end the file is automatically enlarged.
The Seek method provides extended navigation tasks.
See also: Seek
Defines the text line separator. This allows the ReadText method to recognize the lines in text files and WriteText to write correct lines when called with 1 option.
File.textLineSeparator = variable
variable = File.textLineSeparator
The default value is the Windows default line separator -
The separator can be used in different ways depending on the option used with the ReadText and WriteText methods. See their options for more information.
The line delimiter cannot exceed 16 characters.
Set/get Unicode text manipulation option for the File. This option tells the File object how to read and write text.
File.unicodeText = boolean
variable = File.unicodeText
The default value is False (Ansi).
If the property is true all the text methods will use unicode when reading or writing. If False, the text will be converted using the code page specified by the CodePage property.
Specifies the code page used for text operations when configured to use ANSI text.
File.codePage = value
variable = File.codePage
Default is: cpAnsi (ANSI code page)
Const cpAnsi = 0 ' ANSI code page Const cpOem = 1 ' OEM code page Const cpMac = 2 ' MAC code page Const cpSymbol = 42 ' Symbol code page 'Specific code pages - if they are not installed on the system conversions will fail Const cpThai = 874 Const cpJapanese = 932 Const cpChinese = 936 Const cpKorean = 949 Const cpChinese2 = 950 Const cpEasternEuropean = 1250 Const cpCyrillic = 1251 Const cpWestern = 1252 Const cpGreek = 1253 Const cpTurkish = 1254 Const cpHebrew = 1255 Const cpArabic = 1256 Const cpBaltic = 1257
Code page specifies how the text is converted from/to ANSI characters (more precisely UNICODE to/from multibyte conversions).
See also: ReadText.
Indicates it the end of the file is reached.
variable = File.EOS
True value means the current position is at or after the end of File.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") ' Open exiting text file ' Read it line by line While Not File.EOS MsgBox File.ReadText(-3) Wend
Pay attention to the methods that change the file position. The file position is changed by: ReadText, WriteText, WriteBin, ReadBin, Pos, Seek.
Specifies the maximum size of the internal buffer used for text operations (mostly the read operations).
File.maxTextBuff = value
variable = File.maxTextBuff
Positive number (in bytes). Default is 1048576 bytes (1 meg).
Usually 1 megabyte buffer will be enough for reading lines or other portions of the file as text. If you expect bigger portions to be read/written at once set this property to a greater value.
Returns info object for the File.
Set info = File.stats
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") Set info = File.stats MsgBox "Last accessed: " & info.Accessed MsgBox "Last modified: " & info.Modified
The members of info are:
- info.name - Name of the file or storage
- info.Type - Type of the File.
- info.Size - Size of the file
- info.Modified - Last modified time
- info.Created - Created time
- info.Accessed - Last accessed time
- info.Mode - Supported open modes
- info.valid - Is the object valid
Reads the number of bytes specified.
variable = File.ReadBin(bytes)
bytes - integer number specifying the number of bytes to read.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") bin = File.ReadBin(100) ' Reads 100 bytes from the file
The bytes read are packed in a VARIANT binary array (VT_ARRAY | VT_UI1). The result can be passed to any property or method expecting binary data. You can pass the result directly to the WriteBin method.
If the end of file is reached during the read operation the number of the bytes returned will be less than the number of bytes requested.
Writes binary data to the File.
variable = File.WriteBin(data)
data - The data to write to the File. As usual in all similar methods the binary data is expected to be array of bytes (i.e. VT_ARRAY | VT_UI1).
returned value - the number of bytes written to the File.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") nBytes = File.WriteBin(someBinaryData) File.Close
Implements navigation through the file (more extended than the functionality supplied by the Pos property)
variable = File.Seek( position, origin)
position - positive or negative numeric value - the position to navigate to
origin - a constant, specifies how to calculate the physical position over the supplied position parameter. The constants are:
0 Position must be positive and specifies the file position (in bytes) calculated from the beginning of the File. 1 Position can be positive or negative. The file position is moved forward (positive) or backwards (negative) from the current file position. 2 Calculated from the end of File. Positive values will enlarge the file size.
returned value: The resulting absolute position of the File.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") File.Seek(10,0) ' Going to the 10-th byte in the file MsgBox File.ReadText(5) ' Read 5 characters ' Skipping 10 more bytes after the last read character pos = File.Seek(10,1) ' pos contains the absolute resulting position
The control supports files no greater than 2GB in size.
Note that using the file with SFRecord object bound allows you to navigate the file through the SFRecord object (with record based positioning instead of byte based). However using the Seek method may give you advanced options - to skip some non-standard records or work with files/files which contain records and other data in some of its parts.
Copies the entire file or portion of it to the target File.
variable = File.CopyTo( file, cbBytes)
file - the Target File.
cbBytes - Bytes to copy to the target File.
returned value: The actual number of bytes copied.
AddObject "newObjects.utilctls.SFMain", "FS" Set File1 = FS.OpenFile("C:\MyFile1.txt") Set File2 = FS.OpenFile("C:\MyFile2.txt") File1.Pos = 100 n = File1.CopyTo(File2,100) ' Copies 100 bytes beginning from the 100-th byte in the ' source File.
This method can be used for fast transfer of data between different files.
Used to copy files from different storages - for example file to a file in an OLE file etc.
Reads text from the file (from the current position).
variable = File.ReadText(numChars)
positive number - the specified number of characters will be read.
negative numbers have special meaning:
-2 - The entire file (or remaining portion of it depending on the current position) is read as single string
-1 - One line of text is read. The text line is assumed to end with the line separator as it is specified by the textLineSeparator property.
-3 - Advanced version of the previous (-1). This reads one line but applies more heuristic logic - recommended if you work with text files created by unknown operating system (e.g. the line separator can be different). See remarks.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") ' Open exiting text file ' Read 10 characters MsgBox File.ReadText(10) ' Read one line (non-heuristic) MsgBox File.ReadText(-1) ' Read one line (heuristic) MsgBox File.ReadText(-3) ' Read the remaining file as whole MsgBox File.ReadText(-2)
The text is assumed UNICODE or ANSI depending on the unicodeText property.
When -1 (cReadLine) constant is used the line is assumed to end with the line separator exatcly as it is specified in the textLineSeparator property. Other combinations will not be recognized. However this option does not require file to be seekable (see Seek) and can be used on any file object - external or built-in.
When -3 (cReadLineAny) is used the file should be seekable and the end of line is detected more carefully. The line is assumed to end with any of the characters in the string specified by the textLineSeparator property. It is assumed that the line separator may contain more characters but there are no duplicated characters in it. The method automatically skips the rest of the delimiter using this rule and positions there. Method is proved to work correctly with all the popular text files (MAC, UNIX, Windows). The default setting for the textLineSeparator is good text files coming from MAC, UNIX, Windows.
Writes string to the file at the current position and remains after the last character written.
File.WriteText string [, option]
string - The string to write to the file
option - Defines how the text will be written:
0 (default) - just write the string "as is"
1 - Write the string and place "new line" separator after it.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") ' Write the string File.WriteText "Hello " ' Write the rest of the string and place end-of-line File.WriteText "world!",1
The string will be written using ANSI or UNICODE depending on the unicodeText property. The line seprator is specified by the textLineSeparator property.
Releases the file attached to the File.
AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.txt") bin = File.ReadBin(100) File.Close
This methods allows the application to pass complex data as search patterns. The data is converted to binary sequence of bytes and the actual search is performed. If several alternative sequences are to be searched the method can be instructed to search for any of them (but they must have the same length). See the remarks for details.
Despite the complex features supported by the method there are simple and complex ways to use it. You can choose what suits your needs best.
variable = File.Find(what [, flags [, chunkSize]])
what - What to search for. A variant parameter that accepts almost any possible value and converts it to binary sequence. See the remarks for detailed description.
flags - optional, default is 0. How to perform the search. Appropriate combinations of the following flags can be specified.
0 - After search position on the beginning of the found sequence or stay at the end of file if nothing has been found.
1 - After the search return the original position in the file - where the search began (even on unsuccessful search).
2 - After the search stay after the found sequence. If nothing is found then stay at the end of File.
4 - Find any of the specified chunks. If specified the chunkSize parameter is taken into account if not specified it will be ignored.
chunkSize - optional, default is 0. Takes effect only if 4 is specified in the flags parameter. In this case the byte sequence which is result of conversion of the what parameter to binary is separated into chunks with length chunkSize bytes and each chunk is searched separately. If one of them is found the method returns its position. Note that if the size is specified so that the last chunk is smaller than the others this last chunk will be ignored.
returns: the position in the file if successful or -1 if unsuccessful (nothing found).
Search for the short integer values of 6. It will appear (on x86 based Windows systems) as 00 06 in the binary File.Dim main,strm AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.bin") Do pos = File.Find(CInt(6),&H02) If pos >= 0 Then MsgBox "Found at Pos = [" & pos & "]<BR>" End If Loop Until pos < 0
Search for something more complicated - two textual parts with and binary data between them. For simplicity we search two words - first is at the end of line the second must be in the beginning of the next line in a text File. But this technique can be used for any sequence.Dim main,File AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.bin") Dim a(3) a(0) = "First" a(1) = CByte(AscB(vbCr)) a(2) = CByte(AscB(vbLf)) a(3) = "Second" Do pos = File.Find(a,2) If pos >= 0 Then MsgBox "Found at Pos = [" & pos & "]<BR>" End If Loop Until pos < 0
This piece of code will search for all the occurrences of the words "Cat" and "Dog" in the File. File can be a text file or some kind of binary File.Dim main,File AddObject "newObjects.utilctls.SFMain", "FS" Set File = FS.OpenFile("C:\MyFile.bin") Do pos = File.Find("CatDog",&4,3) If pos >= 0 Then MsgBox "Found at Pos = [" & pos & "]<BR>" File.Pos = File.Pos + 1 End If Loop Until pos < 0
what parameter: The application can pass basic variant types (as numeric values or string) and arrays of them. The data contained in the parameter is converted into binary sequence of bytes. Thus if you pass a binary data it will be used "as is". If string is passed it will be converted as the unicodeText and codePage specify and the result will be treated as sequence of bytes. In case of strings the terminating null character is ignored (this is a binary search method we cannot rely on no preliminary assumption how the strings are recorded in it or you can search partial string etc.). The array passed may contain variants in turn (but not other arrays). This is probably the most useful form for the scripts - it allows you to pass different values which will be converted properly and concatenated into single binary sequence used further.
Note that objects cannot be passed to the method through the what parameter! There is no way to determine how to convert them - thus their default property cannot be resolved. So when using values contained in objects (and most likely in their default properties) the application is responsible to convert them to basic values. In NS Basic this can be done by using the CLng, CByte, CStr and the other conversion functions.
If you are feeling confused by the above requirement consider one example situation - an object with a default property which will return a number, for example 7. Converting it to string and then passing it to this method will result in one byte containing the ASCII code of the character '7' (or two bytes in UNICODE mode), but if you convert it to long integer first (using CLng function) it will result in 4 bytes sequence. Thus the resulting binary sequence searched will be different. This illustrates why there is no way to resolve the default properties of the objects in the method itself.
How the non-string values are converted? They are used as they appear in the memory. If you need complete control on each byte pass array of bytes or array of variants where the important bytes are carefully converted to VT_BYTE subtype by using CByte.
What will happen if you pass array of several strings? All the strings will be converted and concatenated. Then depending on the flags if chunks are used the result will be separated in chunks or searched as whole if chunks feature is not used.
Mixing strings with other data. If you are searching for a byte sequence that consist of textual parts and binary parts - you can describe it by creating an array where the text parts are strings and the non-string parts are represented by elements holding numeric data (bytes for example). This allows the scripting application to specify any possible byte sequence even if the script language itself is not capable of doing so.
It is recommended to use bytes and strings mostly. Do not forget that the longer numeric values can be represented in different manner in the File. For example a short integer value (two bytes) can be represented as the high byte first or contrary its low byte can be first in the memory representation. This depends on how and where the file has been created. Therefore using non-byte numeric values requires you to consider their representation in the memory and evaluate if it is possible the file to contain them in an unexpected form.
String searches are always case sensitive.