
FB II Compiler
PG PRO
Debugging
Memory
System
Mathematics
Resources
Disk I/O
Windows
Controls
Menus
Mouse
Keyboard
Text
Fonts
Drawing
Sound
Clipboard
Printing
Communication
ASM
|
DISK I/O
Parse a DOS file
When getting Information from a MainFrame over a WAN I had line input and input# problems...mainly because of speed. When going through several routers/bridges etc. both were _very_ slow. I went to this type of scheme:
LOCAL
DIM a,counter
DIM TheString$
LOCAL FN ReadText$(myLength)
THESTRING$=""
counter=0
FOR counter=1 TO 50 'knew I would never be beyond
'50 so...
a=PEEK([gCellStrHndl&]+goffset&) 'what is it
INC(gOffSet&) 'advance
LONG IF a=13 OR a=9 'checking for Return or Tab
GOTO "getOut" 'go away without storing it
END IF
THESTRING$=THESTRING$+CHR$(a) ' store the CHR$ of it
'in the local string
NEXT counter
"getOut" 'escape from this puppy
theString$=LEFT$(theString$,myLength) 'make it nice
END FN=TheString$ 'put it out
LONG IF LEN(gFileName$)
OPEN "I",#3,gFileName$,,gFileVol
fileSize&=LOF(3,1) 'figure out how much room you need
gCellStrHndl&=FN NEWHANDLE(fileSize&) 'get a handle for it
LONG IF gCellStrHndl&<>_nil 'got the handle
osErr%=FN HLOCK(gCellStrHndl&) 'parnioa here
READ FILE#3,[gCellStrHndl&],fileSize& 'here is the speedy part
'get it in one move
osErr%=FN HUNLOCK(gCellStrHndl&)
goffset&=0 'set for first char
gSubAction=0 'no more pg stuff
XELSE
osErr%=_mFulErr
gSubAction=0 'don't go to MainOpen
FileSize&=-1 'we won't read any data
END IF
CLOSE #3
WHILE gOffset&<FileSize&
MyLocal$=FN ReadText$(8)
WEND
Don't forget to do something like this when done with your handle:
IF gCellStrHndl& THEN DEF DISPOSEH(gCellStrHndl&)
I stuck in some comments that weren't there so remember you may have lines that feed (RETURN) strangely if you paste this into a project.
In the line FN ReadText$(8) The length of 8 is because I happen to know I was getting different length strings and I didn't want any overflows. You could cut this out of the routine if you have no need. Sounds like you will be looking at 1 at a time and could do the fix right inside FN ReadText.
And...horror of horrors, I am using a global for the Handle to the text, but I use FN ReadText$ many times in my app. (Can I pass the Handle to a FN ???)
This thing cut one 187K read from 15 minutes on a PB 140 to the blink of an eye. Another 20K read was cut from 147 seconds to 4 seconds via modem to a network.
It would take some work, but if you're willing to use Toolbox routines instead of FB's built-in file-handling functions, then I would recommend doing it like this:
* To read the file contents very quickly:
1. Open the file using FN FSpOpenDF:
OSErr = FN FSpOpenDF(fileSpec, _fsRdPerm, @refNum)
2. Set up a parameter block for reading the file:
DIM iopb.50
handle& = FN NEWHANDLE(_maxLineLength)
LONG IF handle&
OSErr = FN HLOCK(handle&)
iopb.ioCompletion& = _nil
iopb.ioRefNum% = refNum
iopb.ioBuffer& = [handle&]
iopb.ioReqCount& = _maxLineLength
iopb.ioPosMode% = &0D80 'Read up to CR
iopb.ioPosOffset& = 0 'start at beginning
END IF
Setting the ioPosMode to &0D80 tells it that you want to read up to the next CR character (or up to _maxLineLength characters, or to the end of file, whichever occurs first). Set _maxLineLength to something big like 1000.
3. Then you can read the lines like this:
DO
OSErr = FN READ(@iopb)
LONG IF iopb.ioActCount& > 0 'ioActCount& = number of char's read
FN ProcessTheLine(handle&, iopb.ioActCount&)
END IF
UNTIL OSErr 'OSErr = _eofErr when end of file reached.
4. Close the file and dispose the handle when you're done:
OSErr = FN CLOSE(@iopb)
DEF DISPOSEH(handle&)
* To find the commas very quickly:
I would recommend that (in FN ProcessTheLine) you pass handle& to FN MUNGER, which is designed to do quick searches on long pieces of text.
Two things to remember:
* The CR at the end of the line is included in the bytes that are read into [handle&].
* If your lines actually are delimited by CR/LF, then the LF will simply show up as the _first_ character on the next line that you read.
Oh, one more thing: FN FSpOpenDF looks like this:
'-----------------------------------------------------------
LOCAL FN FSpOpenDF(@specAddr&, permission, refNumAddr&)
DIM OSErr
` clr.w -(sp)
` move.l ^specAddr&,-(sp)
` move.w ^permission,-(sp)
` move.l ^refNumAddr&,-(sp)
` move.w #$0002,d0
` dc.w $AA52
` move.w (sp)+,^OSErr
END FN = OSErr
'-----------------------------------------------------------
The following code is to put an item in the handle to new handle. It works well for me. The delimiter of the item can changed easily. At first I tried to read all data to the memory, and then chage the CR+LF to CR, usuing the MUNGER function, then pick up the line with CR delimiter and the pick up each item with commna.
LOCAL FN getItem(hndl&,item%,delimiter$)
DIM osErr%
DIM count%,sOfs&,eOfs&,size&,delLen%
DIM newHndl&,state%
newHndl& = _nil
LONG IF hndl&<>_nil
size& = FN GETHANDLESIZE(hndl&)
delLen% = LEN(delimiter$)
count% = 0
eOfs& = -delLen%
DO
INC(count%)
sOfs& = eOfs&+delLen%
LONG IF sOfs&<=size&
eOfs& = FN MUNGER(hndl&,sOfs&,@delimiter$+1,delLen%,_nil,_nil)
XELSE
eOfs& = -1
END IF
UNTIL count%=item% OR eOfs&<0
LONG IF count%=item% AND eOfs&<0 AND item%<>1
eOfs& = size&
END IF
LONG IF eOfs&>=0
size& = eOfs&-sOfs&
newHndl& = FN NEWHANDLE(size&)
LONG IF newHndl&<>_nil
state% = FN HGETSTATE(hndl&)
osErr% = FN HLOCK(hndl&)
osErr% = FN HLOCK(newHndl&)
BLOCKMOVE [hndl&]+sOfs&,[newHndl&],size&
osErr% = FN HUNLOCK(newHndl&)
osErr% = FN HSETSTATE(hndl&,state%)
END IF
END IF
END IF
END FN = newHndl&
|