#84839 - 2002-01-14 09:53 PM
File System Object functions 1.1 (suggestions/comments solicited)
|
New Mexico Mark
Hey THIS is FUN
  
Registered: 2002-01-03
Posts: 223
Loc: Columbia, SC
|
code:
; Development notes: ; ; UDFs: oFile Collection ; Author: W.M. Hinsch (New Mexico Mark) ; Created: 1/11/02 ; Last Mod: 1/19/02 ; Dependencies: None ; ; Note 1 ; I considered adding a level of abstraction by writing an oGetFile() function, ; then passing the file object to the oFileOpen function. ; However, the problem with this is that the file must exist first. It does ; not allow for file creation with the ForWriting option. ; ; Note 2 ; Why the weird "** EOF **" and "** ERR **" error codes in the oFileReadLine ; and oFileRead functions? ; The bottom line is that a read or readline could return anything, including ; numbers reserved for error codes. This helps circumvent that problem. ; It is possible but very unlikely for this to happen under normal ; circumstances. ; ; Note 3 ; In the write test, I find that NUL (ASCII 0) is not written to the test ; file. This may be due to internal KiXtart handling of Nulls. ; ; Note 4 ; I chose the "oFile"FunctionName names to designate that we are working with ; objects. This is a combination of FileSystemObject and File objects, so ; I really wasn't comfortable with FSo/oFS or just "obj"FunctionName. ; "oFile" was a compromise. It shows that we are working with objects and ; files without making the names terribly long. ; ; Note 5 ; This is definitely a "first blush" presentation. Suggestions are welcome. ; Please beat on these and let me know any more limitations and/or program ; errors you find. The contents of this message may be copied and pasted ; in totality for your own testing and modifications. ; ; Note 6 ; Caution: If a file is opened for writing, its contents *will* be deleted. ; This is intended behavior, but use oFileOpen mode 2 with caution. ; ; Note 7 ; Although I'm including all of these, after some real-world testing, I ; recommend mainly using oFileOpen() to make it easier to instantiate (with ; error testing) a file object. Of course, the bytewise read and write ; functions will be handy for those applications. However, in testing ; with a very large file, I found that ; $Line = oFileReadLine($oFile1) ; oFileWriteLine($oFile1, $Line) ; versus ; $Line = $oFile1.ReadLine ; $oFile2.WriteLine($Line) ; ; Showed a 3-to-1 performance gain by eliminating the function overhead and ; passing of string data from and to the functions. ; ; Note 8 ; Not returning a number from, say, a fileopen function is deliberate. The ; error level is set, and that may be tested, if desired. However, I like ; the reduced overhead of not having to assign the function output to a ; variable. ; ; ; The console output from the following tests is: ;FileSpec = C:\DOCUME~1\whinsch\LOCALS~1\Temp\test.txt ; ; ;TEST_FWL ;Writing: "This is line 1." ;Writing: "This is line 2." ;Writing: "This is line 3." ;Writing: "This is line 4." ;Writing: "This is line 5." ;Writing: "This is line 6." ;Writing: "This is line 7." ;Writing: "This is line 8." ;Writing: "This is line 9." ;Writing: "This is line 10." ; ;TEST_FRL ;Reading line 1: "This is line 1." ;Reading line 2: "This is line 2." ;Reading line 3: "This is line 3." ;Reading line 4: "This is line 4." ;Reading line 5: "This is line 5." ;Reading line 6: "This is line 6." ;Reading line 7: "This is line 7." ;Reading line 8: "This is line 8." ;Reading line 9: "This is line 9." ;Reading line 10: "This is line 10." ;Reading line 11: "** EOF **" ;Reading line 12: "** EOF **" ; ;TEST_FRA ;Reading entire file contents. ;This is line 1. ;This is line 2. ;This is line 3. ;This is line 4. ;This is line 5. ;This is line 6. ;This is line 7. ;This is line 8. ;This is line 9. ;This is line 10. ; ;TEST_FW ;0 ;1 2 3 4 5 6 7 8 9 ;10 11 12 13 14 15 16 17 18 ;19 20 21 22 23 24 25 26 27 ;28 29 30 31 32 33 34 35 36 ;37 38 39 40 41 42 43 44 45 ;46 47 48 49 50 51 52 53 54 ;55 56 57 58 59 60 61 62 63 ;64 65 66 67 68 69 70 71 72 ;73 74 75 76 77 78 79 80 81 ;82 83 84 85 86 87 88 89 90 ;91 92 93 94 95 96 97 98 99 ;100 101 102 103 104 105 106 107 108 ;109 110 111 112 113 114 115 116 117 ;118 119 120 121 122 123 124 125 126 ;127 128 129 130 131 132 133 134 135 ;136 137 138 139 140 141 142 143 144 ;145 146 147 148 149 150 151 152 153 ;154 155 156 157 158 159 160 161 162 ;163 164 165 166 167 168 169 170 171 ;172 173 174 175 176 177 178 179 180 ;181 182 183 184 185 186 187 188 189 ;190 191 192 193 194 195 196 197 198 ;199 200 201 202 203 204 205 206 207 ;208 209 210 211 212 213 214 215 216 ;217 218 219 220 221 222 223 224 225 ;226 227 228 229 230 231 232 233 234 ;235 236 237 238 239 240 241 242 243 ;244 245 246 247 248 249 250 251 252 ;253 254 255 ; ;TEST_FR ;001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 ;021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 ;041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 ;061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 ;081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 ;101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 ;121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 ;141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 ;161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 ;181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 ;201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 ;221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 ;241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 ; ;:TEST_CODE ;$FS = "%temp%\test.txt" ;"FileSpec = " + $FS ? ? ;GOSUB TEST_FWL ;GOSUB TEST_FRL ;GOSUB TEST_FRA ;GOSUB TEST_FW ;GOSUB TEST_FR ;$oFile = 0 ;EXIT ; ;:TEST_FWL ;$oFile = oFileOpen($FS, 2) ; Open for write ;IF VarType($oFile) = 9 ; ? "TEST_FWL" ? ; FOR $i = 1 TO 10 ; $Line = "This is line " + $i + "." ; "Writing: " + Chr(34) + $Line + Chr(34) ? ; oFileWriteLine($oFile,$Line) ; NEXT ; oFileClose($oFile) ; Use UDF to close ;ELSE ; "oFile = " + $oFile ? ;ENDIF ;RETURN ; ;:TEST_FRL ;$oFile = oFileOpen($FS) ; Open for read ;IF VarType($oFile) = 9 ; ? "TEST_FRL" ? ; FOR $i = 1 TO 12 ; Attempt to read two more lines than exist ; $Line = oFileReadLine($oFile) ; "Reading line " + $i + ": " + Chr(34) + $Line + Chr(34) ? ; NEXT ; $oFile.Close ; Native close method ;ELSE ; "oFile = " + $oFile ? ;ENDIF ;RETURN ; ;:TEST_FRA ;$oFile = oFileOpen($FS) ; Open for read ;IF VarType($oFile) = 9 ; ? "TEST_FRA" ? ; "Reading entire file contents. " ? ; $aryContents = Split(oFileReadAll($oFile),@CRLF) ; Get file into array ; FOR EACH $Element IN $aryContents ; $Element ? ; NEXT ; oFileClose($oFile) ;ELSE ; "oFile = " + $oFile ? ;ENDIF ;RETURN ; ;:TEST_FW ;$oFile = oFileOpen($FS, 2) ; Open for write (delete prev. contents) ;IF VarType($oFile) = 9 ; ? "TEST_FW" ? ; FOR $i = 0 TO 255 ; "" + $i + Chr(9) ; IF $i - (($i / 9) * 9) = 0 ? ENDIF ; oFileWrite($oFile,Chr($i)) ; NEXT ; $oFile.Close ; ? ;ELSE ; "oFile = " + $oFile ? ;ENDIF ;RETURN ; ;:TEST_FR ;$oFile = oFileOpen($FS) ; Open for read ;IF VarType($oFile) = 9 ; ? "TEST_FR" ? ; $Ctr = 0 ; $Byte = oFileRead($oFile) ; WHILE @ERROR=0 ; $Byte = "" + Asc($Byte) ; $Byte = "" + SubStr("000",1,3-Len($Byte)) + $Byte + " " ; $Byte ; $Ctr = $Ctr + 1 ; IF $Ctr - (($Ctr / 20) * 20) = 0 ? ENDIF ; $Byte = oFileRead($oFile) ; LOOP ; ? ; $oFile.Close ;ELSE ; "oFile = " + $oFile ? ;ENDIF ;RETURN ; FUNCTION oFileOpen($iFile, OPTIONAL $iMode, OPTIONAL $iType) ; Returns open File Object. Error level set as follows ; 0 Success ; -1 Input parameter error ; -2 Could not find file ; -4 Could not instantiate File System Object ; -8 Could not open as text stream ; $iMode: 1=Read, 2=Write/Overwrite Existing File, 3=Append ; $iType: 0=ASCII, -1=Unicode, -2=System Default $iFile = "" + $iFile $iMode = 0 + $iMode $iType = 0 + $iType IF $iMode = 0 $iMode = 1 ENDIF IF $iMode <> 1 AND $iMode <> 2 AND $iMode <> 8 EXIT -1 ENDIF IF $iType < -2 OR $iType > 0 EXIT -1 ENDIF DIM $oFS, $bCreate $bCreate = $iMode & 2 IF NOT Exist($iFile) AND (NOT $bCreate) EXIT -2 ENDIF $oFS = CreateObject("Scripting.FileSystemObject") IF @ERROR EXIT -2 ENDIF $oFileOpen = $oFS.OpenTextFile($iFile,$iMode,$bCreate,$iType) IF @ERROR EXIT -8 RETURN ENDIF ENDFUNCTION ; FUNCTION oFileClose($oFile) ; $oFile is an open file object. It would probably be easier to just do the ; close in the script, but this is included for consistency. ; Returns nothing IF VarType($oFile) <> 9 RETURN ENDIF $oFile.Close EXIT @ERROR ENDFUNCTION ; FUNCTION oFileRead($oFile, OPTIONAL $iBytes) ; $oFile is a file object opened for reading as a text stream. ; $iBytes is how many bytes to read from the file. ; Returns the specified number of bytes from a file (1 byte default) ; or sets an error level $oFileRead = "" $iBytes = 0 + $iBytes IF VarType($oFile) <> 9 EXIT -1 ENDIF IF $iBytes < 1 $iBytes = 1 ENDIF IF NOT $oFile.AtEndOfStream $oFileRead = $oFile.Read($iBytes) ELSE EXIT -1 ENDIF EXIT @ERROR ENDFUNCTION ; FUNCTION oFileReadLine($oFile) ; $oFile is a file object opened for reading as a text stream. ; Returns the line (less the final EOL character) or sets error IF VarType($oFile) <> 9 RETURN ENDIF $oFileReadLine = "" IF NOT $oFile.AtEndOfStream $oFileReadLine = $oFile.ReadLine ELSE EXIT -1 ENDIF EXIT @ERROR ENDFUNCTION ; FUNCTION oFileReadAll($oFile) ; $oFile is a file object opened for reading as a text stream. ; Returns the entire contents of a file as a string or sets an error level. ; Again, a simple $oFile.ReadAll would suffice in the main script. However, ; this function is here for consistency. IF VarType($oFile) <> 9 RETURN ENDIF $oFileReadAll = "" $oFileReadAll = $oFile.ReadAll EXIT @ERROR ENDFUNCTION ; FUNCTION oFileWrite($oFile, $String) ; $oFile is a file object opened for writing or appending as a text stream. ; $String contains the characters to write or append. CR/LFs are not ; automatically added. ; No return value, but sets error level $String = "" + $String IF VarType($oFile) <> 9 RETURN ENDIF $oFile.Write($String) EXIT @ERROR ENDFUNCTION ; FUNCTION oFileWriteLine($oFile, $String) ; $oFile is a file object opened for writing or appending as a text stream. ; $String contains the string to write or append. EOL is added. ; No return value, but sets error level IF VarType($oFile) <> 9 RETURN ENDIF $String = "" + $String $oFile.WriteLine($String) EXIT @ERROR ENDFUNCTION ;
[ 19 January 2002: Message edited by: New Mexico Mark ]
|
|
Top
|
|
|
|
#84840 - 2002-01-15 04:53 AM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Shawn
Administrator
   
Registered: 1999-08-13
Posts: 8611
|
Ok Mark, I've had a go at your UDF's ... here's my very crude version of strings ... $filename points a binary file (i used an old version of kix32.exe) $stringsize is the minimum size requirement for a displayed string (all other strings ignored). here's the code:
break on $filename = "c:\kix32\kix32.exe" ; <--- set this to a binary file $stringsize = 5 ; <--- display strings at least this size
$file = oFileOpen($filename) $s="" $c = asc(oFileRead($file,1)) ; read first byte while not @ERROR ; asc 0-9 A-Z a-z if ($c > 47 and $c < 58) or ($c > 64 and $c < 91) or ($c > 96 and $c < 123) $s=$s+chr($c) else if len($s) >= $stringsize ?$s endif $s="" endif $c = asc(oFileRead($file,1)) loop
$=oFileClose($file)
exit 1
I also slightly modified your oFileRead() function to return 0 (zero) and set the value of @ERROR to -1 (on EOF), just like the builtin file functions (just a thought), here's that:
FUNCTION oFileRead($oFile, OPTIONAL $intBytes) ; $oFile is a file object opened for reading as a text stream. ; $intBytes is how many bytes to read from the file. ; Returns the specified number of bytes from a file (1 byte default) ; or "** EOF **" for end-of-file or "** ERROR **" for other error. $oFileRead = "** ERR **" $intBytes = 0 + $intBytes IF VarType($oFile) <> 9 RETURN ENDIF IF $intBytes < 1 $intBytes = 1 ENDIF IF NOT $oFile.AtEndOfStream $oFileRead = $oFile.Read($intBytes) IF @ERROR $oFileRead = 0 EXIT @ERROR ENDIF ELSE EXIT -1 ENDIF ENDFUNCTION
One observation I have so far is that using UDF's to stream over a binary file introduces a lot of overhead and slows down the script considerably, as an example, replace this line in the script: $c = asc(oFileRead($file,1)) with this: $c = asc($file.read(1)) you should see a noticable difference. not too sure if it's the UDF overhead, or the UDF parm checking that's done ... your call in terms of optimizing ... Thoughts ? -Shawn
|
|
Top
|
|
|
|
#84841 - 2002-01-15 05:36 AM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
New Mexico Mark
Hey THIS is FUN
  
Registered: 2002-01-03
Posts: 223
Loc: Columbia, SC
|
Hi Shawn:I'm still in the "run it up a flagpole" stage of development. I had hoped to do some performance testing tomorrow. The only things I can see gaining so far by using the File System object are: 1. The ability to work with very large files. 2. The ability to work with non-ASCII files and read a file byte-by-byte. Let me look some more at the file object methods and see if there are any more major gains to be had. I'm pretty sure the "pointer" location in the file can be returned. However, any program logic should keep track of this independently. There may be one or two more areas that aren't handled (or handled well for large or binary files) in KiXtart file handling. As for the return codes, I'm still pretty new with KiXtart, and I didn't realize you could raise an error code by "exit"ing the function with an exit code. That solves the problem of return codes conflicting with returned data. Thanks! I'll get some modified code out there tomorrow. New Mexico Mark [ 15 January 2002: Message edited by: New Mexico Mark ]
|
|
Top
|
|
|
|
#84842 - 2002-01-15 05:47 AM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
New Mexico Mark
Hey THIS is FUN
  
Registered: 2002-01-03
Posts: 223
Loc: Columbia, SC
|
BTW, one programming trick frequently used is to pass parameters by reference so input parameters are also output parameters. This bypasses the "one value returned" function limitation. I.e.RC = PlayDough (Mass,CubeSideLen, SphereRadius) (where CubeSideLen and SphereRadius are already defined and set to zero) would set the value of CubeSideLen and SphereRadius based on the Mass provided, as well as an error code as the "return value" of the function. Is it possible to do something similar with KiXtart functions? I'm not sure if KiXtart can differentiate between ByValue and ByReference argument passing. But can it be faked into recognizing the difference? Inquiring minds want to know! New Mexico Mark [ 15 January 2002: Message edited by: New Mexico Mark ] [ 15 January 2002: Message edited by: New Mexico Mark ]
|
|
Top
|
|
|
|
#84843 - 2002-01-15 06:16 AM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Shawn
Administrator
   
Registered: 1999-08-13
Posts: 8611
|
Unfortunately, every parameter passed in a function (user defined or builtin) is passed by value ... even parameters that one wouldn't expect to be passed by value are, for example, read Ruud's comments about UBOUND in this thread (in bold):Pipe - Submits a shell command and redirects output to an array Bottom line was that the UBOUND() function was passing arrays by value - so when checking huge arrays frequently, performance would degrade exponentially ... Ruud has since fixed this "problem" in the latest Beta 4.02 ... This is the only way I can think of to "fake it" :
break on $var = 1
func("$$var") ; <--- pass var by reference
?"var=" $var
exit 1
function func($parm) $=execute("$parm=2") endfunction
-Shawn [ 15 January 2002: Message edited by: Shawn ]
|
|
Top
|
|
|
|
#84845 - 2002-01-15 02:42 PM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Alex.H
Seasoned Scripter
Registered: 2001-04-10
Posts: 406
Loc: France
|
Shawn, NMM, just a question : and if the parameter is defined as global, and is the same name in the function declaration ?[ 15 January 2002: Message edited by: Alex.H ]
_________________________
? getobject(Kixtart.org.Signature)
|
|
Top
|
|
|
|
#84847 - 2002-01-15 03:24 PM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Shawn
Administrator
   
Registered: 1999-08-13
Posts: 8611
|
Alex,Yeah, I had the same thought as you - referencing a global variable from a function is "like" passing it by reference (kind of) ... but there's a BIG difference in the way I coded it as above. Using the above strategy, instead of passing the value of the variable, one passes the variable name itself as the parameter (by reference, it's like passing a pointer). The difference is that the UDF can be coded in a generic fashion. When hardcoding a specific global variable name in a UDF, that UDF will always be bound to that variable ... I'm not saying that this is a viable or usable strategy, just throwing-out ideas and suggesting that this is one way to do it. By way of example, here's a UDF called AddOne() that will add 1 to any variable, without using a single hardcoded global variable ...
break on $Variable1 = 1
AddOne("$$variable1")
?"Variable1=" $variable1
$Variable2 = 2
AddOne("$$variable2")
?"Variable2=" $variable2
exit 1
function AddOne($varbyref) dim $local $=Execute("$$local=$varbyref") ; assign global variable (value) to local $local = $local + 1 $=Execute("$varbyref=$local") endfunction
The global variable approach would have us do something like this (which is probably the better, easier, more understandable way anyways) : $AddOneVar = $Variable1 AddOne() $AddOneVar = $Variable2 AddOne() Of course, AddOne() is a bad example to use here because normally, one wouldn't use global variables in a UDF that just adds one to a parmeter. This is just an example. -Shawn [ 15 January 2002: Message edited by: Shawn ]
|
|
Top
|
|
|
|
#84850 - 2002-01-15 04:11 PM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Shawn
Administrator
   
Registered: 1999-08-13
Posts: 8611
|
Well, in the meantime, we could probably formalize a standard for passing values by reference, like this example UDF called Add() that adds the first parameter (byval) to the second (byref) ... it would just have to be understood how one used the function. Not a normal function by any stretch of the imagination 
break on $Number = 2
Add(10,"$$Number")
?"Number=" $Number
exit 1
function Add($Var1,$Var2ByRef) ; ; Add Var1 to Var2 (byref) and put result back into Var2 (byref) ; $ = Execute("$Var2ByRef = $Var1 + $Var2ByRef") ; do it endfunction
I was hoping we could have just gotten away with this syntax: Add(10,$$Number) and I thought that maybe when kixtart would have seen the double-dollar sign, it would have treadted $$Number as a string "$$Number" ... too back but it didn't work ... but it might be a good suggestion to Ruud (if he did decide to ever implement passing byref), for example saying this: Function Add($Var1,$$Var2) ... EndFunction is the same as saying this: Function Add($Var1,$Var2 ByRef) ... EndFunction [shrug] -Shawn
|
|
Top
|
|
|
|
#84852 - 2002-01-16 02:10 AM
Re: File System Object functions 1.1 (suggestions/comments solicited)
|
Alex.H
Seasoned Scripter
Registered: 2001-04-10
Posts: 406
Loc: France
|
Lonkero, don't be scared, even if I actually know the differences between them, I sometimes smell smoke too. This one would be great, but as the actual way of kix-programming is not by using pointers, it would only be used in some specials case.On the other hand, it would ensure us to stay as we are the only one that can understand this f$ù^* script 
_________________________
? getobject(Kixtart.org.Signature)
|
|
Top
|
|
|
|
Moderator: Shawn, ShaneEP, Ruud van Velsen, Arend_, Jochen, Radimus, Glenn Barnas, Allen, Mart
|
0 registered
and 2312 anonymous users online.
|
|
|