Announcement

Collapse
No announcement yet.

Random Write - Variable - Example Bug

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mike Trader
    replied
    Borje,
    Im so sorry, you are right. I was having difficulty seeing what you did. This will work great. I rewrote it a little for my needs and for anyone following this thread later.

    Thank you all so much. I got there - eventually!

    #COMPILE EXE "Random.exe"
    GLOBAL Header AS STRING * 10 '<- determins length of header line
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤'
    FUNCTION PBMAIN
    Local I AS LONG, Contents AS STRING
    '---------------------------------'Create a file
    OPEN "RANDOM.DTA" FOR OUTPUT AS #1
    Header = "Header-to-be-overwritten" '<- Only first 10 chars will be written
    PRINT #1, Header
    FOR I = 1 TO 13
    WRITE #1, I,0,0,454,22,0,0,34,54,1,1,0,0
    NEXT
    CLOSE #1
    '------------------------------' Show file Contents
    OPEN "RANDOM.DTA" FOR BINARY AS #1
    Contents = SPACE$(LOF(1))
    GET #1,, Contents
    CLOSE #1
    MSGBOX Contents
    '---------------------------------'Change header
    OPEN "RANDOM.DTA" FOR BINARY AS #1 BASE = 0
    Header = FORMAT$(I-1)+"-Lines-in-this-file" '<- New text - Only first 10 chars will be written
    SEEK #1, 0 '<- set position to Beginning of first record
    PUT #1,, Header '<- put the new string (Must be the same length! - 10 Chars)
    CLOSE #1
    '------------------------------' Show file Contents
    OPEN "RANDOM.DTA" FOR BINARY AS #1
    Contents = SPACE$(LOF(1))
    GET #1,, Contents
    CLOSE #1
    MSGBOX Contents

    END FUNCTION
    '-------------------------------------------

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    I don't understand. If you use my last sample, you can change any
    record with the help of SEEK and PUT. No need to read whole file
    into memory, even though 100KB isn't much today..


    ------------------

    Leave a comment:


  • Michael Mattias
    replied
    It is becoming obvious that RANDOM was designed for Binary read/Write and not Ascii data like the INPUT# and WRITE# cousins.
    No, that's not correct. The *type* of data - printable or unprintable - has nothing to do with the *access mode* used (except as below).

    INPUT# and WRITE#/PRINT# were designed for *sequential* access.

    PUT/GET/SEEK were designed for random (small letters) access.

    The only place data "type" makes a difference is in the INPUT# or LINE INPUT# verbs, where the verb means, "read from the current file pointer forwar up to the next comma/CRLF/EOF and advance the pointer beyond the delimiter." Consequently, you cannot use these verbs with data which may be *interpreted* as one of the delimiter characters.

    The so-called "binary" representation of the the integer value 13 would be interpreted as CHR$(13) + CHR$(0) , or carriage return, nul; so LINE INPUT$ should not be used to get the value of 16-bit integers expressed in native ("binary") format.

    MCM

    Leave a comment:


  • Mike Trader
    replied
    Thx Lance, But I have to adhere to the file format im trying to emulate ie all Ascii charaters/Numbers

    Borje,
    Thx for that example. I have examined it carefully. I am trying to avoing reading 100k lines into memory tho.

    I think I must simply create another file and reall all the lines one by one in and write them to the new file.

    It is becoming obvious that RANDOM was designed for Binary read/Write and not Ascii data like the INPUT# and WRITE# cousins.

    Thx again

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    There many ways to do this. Problem is you need the file to be like
    ordinary text file, if I have understood this correctly. If each
    record (line) has same length, the following may give you an idea
    of a better way:
    Code:
    #COMPILE EXE "Random.exe"
     
    TYPE TestRec
      uName   AS STRING * 10
      uNumber AS STRING * 10
    END TYPE
     
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤'
    FUNCTION PBMAIN
    LOCAL I AS LONG, hString AS STRING, Rec AS TestRec
     
    'Create test file
    OPEN "RANDOM.DTA" FOR OUTPUT AS #1
      PRINT #1, SPACE$(10)
      FOR I = 1 TO 3
         Rec.uName = "Joe" + STR$(I)
         Rec.uNumber = FORMAT$(I)
        PRINT #1, Rec.uName
        PRINT #1, Rec.uNumber
      NEXT
    CLOSE #1
     
    'Test to see whole file
    OPEN "RANDOM.DTA" FOR BINARY AS #1
       hString = SPACE$(LOF(1))
       GET #1,, hString
    CLOSE #1
    MSGBOX hString
     
    'Change header
    OPEN "RANDOM.DTA" FOR BINARY AS #1 BASE = 0
       hString = FORMAT$(I - 1)     '<- Change header
       PUT #1,, hString
     
       I = 1
       Rec.uName = "Borje" + STR$(I)
       SEEK #1, I * 12               '<- set position to first record
       PUT #1,, Rec.uName            '<- put changed data
    CLOSE #1
     
    'Test to see whole file
    OPEN "RANDOM.DTA" FOR BINARY AS #1
       hString = SPACE$(LOF(1))
       GET #1,, hString
    CLOSE #1
    MSGBOX hString
     
    END FUNCTION

    ------------------

    Leave a comment:


  • Lance Edmonds
    replied
    Personally, I'd "reserve" a fixed number of bytes at the beginning of the file, using some muliple of the actual data record size.

    Then you can write to that portion of the file with BINARY mode, and reopen the file in RANDOM mode and read the records.

    For example, if your record is 32 bytes, reserve the 1st two records for the "ascii" data, and start your real records at byte 65 (record 3). You could also read/write the records in binary mode too - what ever is easier for you. The following technique will enable the first 24 bytes to be read with LINE INPUT if required.
    Code:
    ' pseudocode:
    TYPE TestRec
      uName AS STRING * 10
      uNumber AS INTEGER
    END TYPE
     
    TYPE HeaderRec
      Header AS STRING * 22 ' (10 + 2) * 2 - 2
      Terminator AS STRING * 2
    END TYPE
      
    Dim Rec AS TestRec
    Dim Header As HeaderRec
     
    Header.Header = "Record Count = " + FORMAT$(RecCount&)
    Header.Terminator = $CRLF
     
    OPEN file$ FOR BINARY AS #1
     PUT$ #1,, Header
    CLOSE #1
    
    OPEN file$ FOR RANDOM AS #1
     FOR x& = 3 to (LOF(1) - LEN(Header)) \ LEN(Rec)
      GET #1, x&, Rec
      '... process Rec
     NEXT x&
    CLOSE #1
     
    ' Now read the first two records as you would a sequential file.
    OPEN file$ FOR INPUT AS #1
     LINE INPUT #1, a$
     MSGBOX a$
    CLOSE
    Anyway, I hope you get the idea.


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Mike Trader
    replied
    Borje,
    Thanks so much for that example. That will work but it seems crazy to have to read the whole file into memory just to write the first line.

    I might as well just read each line of the file and write it to a new file. That way I can write the first line with all the data needed.

    Also If I use a file with 1min data, thats 405 lines per day, 5 days per week, 52 weeks per year = 105300. I need to go back at least 4 years so thats 421000 lines.

    I would much rather find a way to over write the first line!

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    Okay, so a bit more complicated, if each line must be separate string
    and first line hold file data in form of a string. Forget SEEK. Here's
    a way of doing it - involves reading entire file into an array:
    Code:
    LOCAL I AS LONG, J AS LONG, hString AS STRING, tmp AS STRING, Rec() AS TestRec
     
    'Create first instance of test file
    OPEN "RANDOM.DTA" FOR OUTPUT AS #1
      PRINT #1, FORMAT$(I) 'empty line, for file data
      FOR I = 1 TO 3
        PRINT #1, "Joe" + STR$(I)
        PRINT #1, FORMAT$(I)
      NEXT
    CLOSE #1
     
    'Read test file into array
    I = 0
    OPEN "RANDOM.DTA" FOR INPUT AS #1
      IF LOF(1) THEN LINE INPUT #1, hString 'read file data separately
      DO WHILE NOT EOF(1)
         IF I MOD 20 = 0 THEN REDIM PRESERVE Rec(I + 20)
         LINE INPUT #1, Rec(I).uName
         LINE INPUT #1, tmp
         Rec(I).uNumber = VAL(tmp)
         INCR I
      LOOP
      DECR I
      REDIM PRESERVE Rec(I)
    CLOSE #1
    MSGBOX hString & $CRLF & Rec(0).uName & STR$(Rec(0).uNumber)
     
    'Write all back, including first line data
    OPEN "RANDOM.DTA" FOR OUTPUT AS #1
      PRINT #1, FORMAT$(I) 'print file data separately
      FOR J = 0 TO I
        PRINT #1, Rec(J).uName
        PRINT #1, FORMAT$(Rec(J).uNumber)
      NEXT
    CLOSE #1
     
    'Check to see that it worked
    I = 0
    OPEN "RANDOM.DTA" FOR INPUT AS #1
      IF LOF(1) THEN LINE INPUT #1, hString
      DO WHILE NOT EOF(1)
         IF I MOD 20 = 0 THEN REDIM PRESERVE Rec(I + 20)
         LINE INPUT #1, Rec(I).uName
         LINE INPUT #1, tmp
         Rec(I).uNumber = VAL(tmp)
         INCR I
      LOOP
      REDIM PRESERVE Rec(I - 1)
    CLOSE #1
    MSGBOX hString & $CRLF & Rec(0).uName & STR$(Rec(0).uNumber)

    ------------------


    [This message has been edited by Borje Hagsten (edited March 04, 2001).]

    Leave a comment:


  • Mike Trader
    replied
    No can do Bern. First Line has to contain all the pertinant info about the file and the data in the file. Thats the format im trying to emulate.

    Of course I could just copy the first file to a second file and write the first line correctly as I do it, but for 10k+ lines that seems kinda lame.

    It must be possible to write randomly to a file without being constrained to Binary data surely?

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Bern Ertl
    replied
    Mike, perhaps it would be easier to create a second file to
    contain statistics / pointers for the first file?



    ------------------
    Bernard Ertl

    Leave a comment:


  • Mike Trader
    replied
    Sorry Borje, that went right over my head. Can you use my example to show me pls

    Actually, I have 3 or 4 variables to write on the first line. the first of which is the total number of lines in the file.

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    Look up the SEEK command. You can place a header at the beginning
    of a file, like a full structure or a variable, using PUT/GET, then
    use SEEK to set position to proper place and WRITE/INPUT whatever
    you need.

    If header is just one LONG, PUT/GET it at beginning of file, then
    use, SEEK #1, 4 to set position for further WRITE/PRINT/INPUT..

    Correction: Should be SEEK #1, 5, unless you have you used BASE = 0
    on the OPEN line (according to PB's helpfile).
    ------------------


    [This message has been edited by Borje Hagsten (edited March 04, 2001).]

    Leave a comment:


  • Mike Trader
    replied
    OK thx but I tried that. There is a problem - it overwrites my data!

    Here is a much better example of what i am trying to do. The problem is evident in the .dta file

    #COMPILE EXE "Random.exe"

    GLOBAL Line1Str AS STRING * 10
    GLOBAL Record AS LONG, Count AS LONG
    GLOBAL SomeVar1 AS LONG, SomeVar2 AS LONG
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤'
    FUNCTION PBMAIN

    OPEN "RANDOM.DTA" FOR OUTPUT AS #1
    FOR Record=3001 TO 3014
    SomeVar1 = VAL(DATE$)
    SomeVar2 = VAL(TIME$)
    WRITE #1, Record-3000, 0, 0, 0, SomeVar1, 0, 0, SomeVar2, Record
    INCR Count
    NEXT
    CLOSE #1

    '--------------- write the number of lines on Line 1

    OPEN "RANDOM.DTA" FOR RANDOM AS #1 LEN = LEN(Line1Str)
    Line1Str = LTRIM$(STR$(Count))
    PUT #1, 1, Line1Str
    CLOSE #1

    END FUNCTION
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤'

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    If you want to put a variable in ASCII format, change the declared
    type to something like:
    Code:
    TYPE TestRec
      uName   AS STRING * 10
      uNumber AS STRING * 10
    END TYPE
    ..and convert the variable to string format before you PUT it into the
    record. Better to use the way you do, though, and convert to string
    after GET command, using FORMAT$(Rec.uNumber). STR$(), used in my
    sample adds a leading space, so better to use FORMAT$ for other use than
    showing in MSGBOX..


    ------------------

    Leave a comment:


  • Mike Trader
    replied
    Borje,
    Yes that worx - thx, but the Ascii File Random.dta must be readable in ascii format for another EXE.

    I need to find a way to overwrite the first record with an ascii number. Is the only way to do this with the number converted to a string?

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Mike Trader
    replied
    Don,

    It doesnt say that Variables are stored in Binary format in the manual, but to answer your question I was hoping to see:
    1 2 3
    I am creating an ascii file. Every other line is Ascii format.

    So i guess the question becomes, how do I PUT a variable in ascii format, (just like all the variables written to the file with
    WRITE# )

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Borje Hagsten
    replied
    Add the following to your code, after file is closed after writing,
    and see that it works.
    Code:
    OPEN "RANDOM.DTA" FOR RANDOM AS #1 LEN = LEN(TestRec)
      GET #1, 3, Rec 'Get third record
      MSGBOX Rec.uName & STR$(Rec.uNumber)
      GET #1, 2, Rec 'Get second record 
      MSGBOX Rec.uName & STR$(Rec.uNumber)
    CLOSE #1

    ------------------

    Leave a comment:


  • Mike Trader
    replied
    Yes I get Joe1 Joe2 and Joe3
    BUT those are the strings. The VARIABLE should also be after each "Joe" all I get is three "  "

    FYI I am writing an app that converts 10k lines of data. It creates a new file in the process. After the file is created I want to go back in and insert the total number of lines in the file on the first line for the next EXE to read

    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Don Dickinson
    replied
    What are you expecting to see? Integers are stored in 2-byte binary represenation. The number one is actually stored as chr$(0) + chr$(1) (did i get that right? i always get my endians mixed up )
    When you open the random file in a text editor you won't see a 1, you'll see a ch$(0) + chr$(1) - these are not human readable via a text editor (a hex-editor, yes, but not a text editor).
    Best Regards,
    Don


    ------------------
    www.basicguru.com/dickinson

    Leave a comment:


  • Paul Squires
    replied
    I just ran the example and looked at the resulting "random.dta"
    file and I could see Joe 1, Joe 2 and Joe 3 in the file. There
    must be something else coming into play on your end????

    ------------------
    Paul Squires
    mailto:[email protected][email protected]</A>

    [This message has been edited by Paul Squires (edited March 04, 2001).]

    Leave a comment:

Working...
X