![]() |
Forum Index : Microcontroller and PC projects : Quirk in the INPUT #n command.
Author | Message | ||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
This is interesting. INPUT #n won't read a comma separated list of values in separate statements in a loop from a file. The following code, run under DOS, will generate two data files "TEST1.DAT" and "TEST2.DAT". It will read the values in the second file, but not in the first. How do you make an INPUT # command in a loop read a comma separated list? Paul in NY Option base 1 Dim T%(10) For i%=1 To 10:T%(i%)=i%:Next For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10" Open "test1.dat" For output As #1 For i%=1 To 10 Print #1, Str$(T%(i%)); '<<<<<<<<<<<< writes "1,2,3,4,5,6,7,8,9,10" to file If i%<10 Then Print #1,","; Next Close #1 Open "test1.dat" For input As #1 For i%=1 To 10 Input #1, T%(i%) '>>>>>>>>>>>>>>>>>>>>>>>>>>>> reads "1,0,0,0,0,0,0,0,0,0" Next Close #1 For i%=1 To 10:Print T%(i%),:Next:Print '>>>>> "1 0 0 0 0 0 0 0 0 0" For i%=1 To 10:T%(i%)=i%:Next For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10" Open "test2.dat" For output As #1 For i%=1 To 10 Print #1, Str$(T%(i%)) Next '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;>>> writes one value to each of ten lines Close #1 Open "test2.dat" For input As #1 For i%=1 To 10 Input #1, T%(i%) '>>>>>>>>>>>>>>>>>>>>>>>>>>> reads "1,2,3,4,5,6,7,8,9,10" Next Close #1 For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10" |
||||
Justplayin![]() Guru ![]() Joined: 31/01/2014 Location: United StatesPosts: 328 |
To read a line of data at a time use LINE INPUT #n instead. --Curtis I am not a Mad Scientist... It makes me happy inventing new ways to take over the world!! |
||||
flip Senior Member ![]() Joined: 18/07/2016 Location: AustraliaPosts: 114 |
Agreed I have noticed this too, and worked around with routines for the purposes To further amplify the point, the following works Open "test1.dat" For input As #1 Input #1, T%(1), T%(2), T%(3), T%(4), T%(5), T%(6), T%(7), T%(8), T%(9), T%(10) Close #1 For i%=1 To 10:Print T%(i%),:Next:Print '>>>>> "1 2 3 4 5 6 7 8 9 10" It's as if the Input command reads a line...interesting to see what happens if the CSV line is >255 (not tested running out of time) Of course I'm sure you worked out there are some ways to workaround this. LINE INPUT #hF,buf$ (if you know the limes are always 255 chars or less) buf$=INPUT$(n,#hF) Both are a little tricky as you need to manage EOF but you can hide the untidiness in a routine. Regards Phil |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
I guess there's no way to read sequential comma delimited variables from one line using a loop to cycle through array positions. The INPUT # command insists on moving its pointer to the next line when it terminates. I wonder if Geoff could figure out a way to modify this behavior. Right now when INPUT encounters a comma in the data source line it continues along the source line to read the next variable as long as there are remaining variables in the {INPUT #n,V1,V2,V3,...,Vn} line. It moves the data pointer to the next line at the end of the INPUT line. If the command line terminated with a comma {INPUT #n,V1,V2,V3,} would it be possible to not move the data pointer? Then this code { for i=1 to 10:input #1,T%(i),:next } would read a data line like {DATA 1,2,3,4,5,6,7,8,9,10} with no trouble. Paul in NY |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
If you know how many values on each line, read that many at a time. If you don't know how many, look at the function written by Geoff to split up the fields of a GPS stream. It can be easily used to do what you are trying to achieve (if I read the problem correctly). Jim VK7JH MMedit |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
Hi Jim, The file contains 167 integers which are the calibration variables for my geothermal program. Most of them are contained in arrays within the program. I was planning on writing them out in rows and columns to simulate the arrays so that hand editing of the data file would be convenient. Using LINE INPUT #n to read the lines and then splitting the line at the commas seems inconvenient because the lines would not all be the same length. I decided to write the file with one variable per line followed by a comma and text to identify the variable. This will enable hand editing of the file if it is needed, and it will also simplify reading the file with simple INPUT #n commands in loops. I've written the needed code and tested it and it seems usable. Paul in NY |
||||
robert.rozee Guru ![]() Joined: 31/12/2012 Location: New ZealandPosts: 2442 |
the use of INPUT #n,V1,V2,...,Vn, (with a trailing comma) seems logical, as it would match the way the PRINT statement works. this could be a worthwhile addition geoff may like to think about adding to the language. another thing i have been thinking about over the last few days is the usefulness of having a constant called "NaN". NaN is a floating point constant, the name standing for 'not a number'. it is an invalid bit pattern that can NOT be obtained as a result of any calculation, and as such can be quite useful in detecting if a floating-point variable has had nothing assigned to it. for instance: Do A=NaN Input "enter a number ", A If A=NaN Then Print "no number entered" Else Print "you entered ";A EndIf Loop without the line A=NaN the interpreter's behaviour could easily be made the same as for standard basic (where just pressing enter results in A being assinged the value 0.0). unfortunately, integer variables do not have invalid bit patterns available, so there is no integer equivalent to NaN. cheers, rob :-) |
||||
flip Senior Member ![]() Joined: 18/07/2016 Location: AustraliaPosts: 114 |
Hi Paul, I had some time to test more and, as we both guessed it is a line read per INPUT # statement. There is no way you can use INPUT# or LINE INPUT# to read 167 integers because internally both statements are limited to lines of 255 characters. I now recall Geoff mentioning this limitation before...demonstrated as follows open "Test3.dat" for output as 1 Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)","; Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)","; Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)","; Print #1, Str$(1/7) close #1 'This file is a single line of 260 bytes ' EVEN reading ONE variable will fail the program Open "test3.dat" For input As #1 Input #1,T%(1) '[47] Input #1,T%(1) 'Error: Line is too long Close #1 Geoff's answer (if I recall correctly) is that the intent is that the INPUT statement was only intended to read/save a few values, not intended to support a full blown DB, therefore he wasn't planning to address it. That said, other methods may work more efficiently. The methods depend on whether speed or minimum storage is the more critical requirement. I've used both..following is what I use for minimal number of bytes (depending on integer value range required) Function IntToChr(iVal As INTEGER,nChrs As INTEGER) As STRING ' Converts an unsigned INTEGER TO a character STRING of length nChrs ' little-endian ' nChrs must be between 1 and 8 (no bounds checking because this is an internal function) Local As INTEGER iTmp=iVal Local As INTEGER iRmndr Local i As INTEGER For i=1 To nChrs iRmndr = iTmp Mod 256 iTmp = iTmp \ 256 IntToChr = Chr$(iRmndr) + IntToChr Next i End Function Function ChrToInt(sVal As STRING) As INTEGER ' Inverse FUNCTION of IntToChr (little-endian) Local i As INTEGER For i=1 To Len(sVal) ChrToInt = 256*ChrToInt + Asc(Mid$(sVal,i,1)) Next i End Function Option Base 1 ElementByteSize%=3 rows%=30 cols%=267 Dim a%(rows%,cols%) 'Load up array values for later checking and write to file Open "test4.dat" For Output As #4 For i%=1 To rows% For j%=1 to cols% a%(i%,j%)=i%*10000+j% Print #4,IntToChr(a%(i%,j%), ElementByteSize%); Next j% Next i% Close #4 Open "test4.dat" For Input As #4 For i%=1 To rows% For j%=1 to cols% elem%=ChrToInt(Input$(ElementByteSize%,#4)) If (i%=1 and j%=1) or (i%=rows% and j%=cols%) then Print "element"i%","j% " when read back is" elem% ", should be same as written:"a%(i%,j%) If elem%<>a%(i%,j%) Then Print "FAIL!!! element"i%","j% " when read back is" elem% ", should be same as written:"a%(i%,j%) Next j% Next i% Close #4 Regards, Phil |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
That's what I thought. The INPUT command must read the entire line of code at one time. It then has to scan the code line for delimiters (",") to decide if it has to accept multiple variables. Assuming it finds multiple variables it would probably then read the data line until it finds a delimiter (",") then evaluate the line thus far while leaving the pointer paused. The process would then repeat until either the variables in the code line are exhausted or until the data line ends. What I'm doing now, writing each variable to its own line followed by human readable identification, which enables manual editing of the data file, like this, 999, S%(1,1), and then reading it in a loop with the command, INPUT S%(i%,j%)", seems to work, but I'm not sure why. When INPUT is expecting a numeric value I think it uses VAL() to find the 999 and then ignores the rest of the line after the first non-numeric character , S%(1,1)}. Can you clarify the operation of the INPUT command? Does it read the data line until it finds a non-numeric character then quit? Exactly what characters are guaranteed to cause it to quit reading? For example, would a "|" or "," or ">" always work? These are a few lines from the 173 line calibration data file which I am using currently. 35, S%(1,1) 120, S%(1,2) 35, S%(1,3) 125, S%(1,4) 5, S%(1,5) 35, S%(2,1) 120, S%(2,2) 35, S%(2,3) Paul in NY |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |