CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Jun 2011
    Posts
    14

    WRITE to a file in a specific location

    Hello:

    I have some code that reads to a certain record in a text file, then extracts that record. That all works fine.

    Now I need to OVERWRITE that same record once it is used.

    How do I open the file as Output, read to a location then write over it? I hope this is possible without have to parse the file into temp files.
    Code:
    ' This section works as designed. It goes to a random record in the file
    Open GcmdTMKFile For Input As #1
    Randomize
    intRandom = Int((GintRecCount * Rnd) + 1)    ' Generate random value between 1 and TmpRecCount
    ' Loop through file until you get to the TmpRandom Record, then exit FOR NEXT LOOP
    For X = 1 To intRandom
        Line Input #1, strRecord
    Next
    Close #1
    strTMKRecord = strRecord
    ' Now I need to write "XXXXX" over the record I just extracted

    Code:
    Open GcmdTMKFile For Output As #1
    For X = 1 To intRandom
        Line Input #1, strRecord   ' I get an error because I have opened the file for Output
    Next
    Print #1, "XXXXX"
    Close #1
    Any help is greatly appreciated.

    thanks.
    kpierce

  2. #2
    Join Date
    Jan 2006
    Location
    Fox Lake, IL
    Posts
    15,007

    Re: WRITE to a file in a specific location

    That would be BINARY MODE, which means one extra length title will overwrite the next track. Not a good idea.

    Other approach, use TWO files, read one, and write the other.
    David

    CodeGuru Article: Bound Controls are Evil-VB6
    2013 Samples: MS CODE Samples

    CodeGuru Reviewer
    2006 Dell CSP
    2006, 2007 & 2008 MVP Visual Basic
    If your question has been answered satisfactorily, and it has been helpful, then, please, Rate this Post!

  3. #3
    Join Date
    Jul 2008
    Location
    WV
    Posts
    5,362

    Re: WRITE to a file in a specific location

    It depends on what your file will be like. If the records are fixed lenght then you can use a random access file which would be the best and fastest way possible. With RA files you can read or write a specific record at will. With standard file methods you would need to open the file for input to read your data then open the file for output to write the data. To change a record in this type of file requires the file be rewritten so you either need to use a tmp file or read all the data into memory before attempting to write to the file.

    Binary access is also an option in which you can seek to a specific location within the file and write data to it. This will cause issues if the data you are writing is not the same length as that which was there before. If you new data is shorter then some of the old record will still exist in the file unless of course you padd your new data with spaces to fill the space of the old record. Worse if the new data is longer then will will overwrite part of the data in the next record and corrupt your file. Proper planning must be done to use this type of file as well as the random access methods.
    Last edited by DataMiser; December 21st, 2011 at 02:35 AM.
    Always use [code][/code] tags when posting code.

  4. #4
    Join Date
    Jun 2011
    Posts
    14

    Re: WRITE to a file in a specific location

    Thanks to everyone for the help.

    I will always know the length of a record, it will be fixed based on the file created and each record/row/field will be 4-9 characters in lengh.

    I am not a wiz and am trying to simply apply a change without having to redesign file layouts or other areas of the code. I really appreciate all the help.

    Let me give you an example:
    TEST.TXT
    1234
    5678
    2345
    7654
    6543

    The first part of the code reads to a random 'record' number and loads that records value into a variable. For example the random record is 3, which contains 2345.

    So the program now closes the file. (This is the old code, this is all working fine).

    Now the change is I need to go back into record 3 and write over the value 2345 with ZZZZ.

    So the file now becomes:
    1234
    5678
    ZZZZ
    7654
    6543

    I think I understand you are saying write the top of the file to a tempfile:
    1234
    5678

    Then write ZZZZ

    Then write the remainder of the file.

    It seems like there should be a way I can get my location in the file when it is OPENed as OUTPUT, store that into a variable, example TmpLocation with the SEEK(1) function

    Then CLOSE it and reOPEN it as BINARY/INPUT/RA, etc. and go directly to the position that was stored in TmpLocation.

    The reason I want to try this way, is these files can become large (40Meg) in size and the program is already extremely slow.

    Again, I really appreciate everyones support and guidance.

    I have the following code to this point:

    Code:
       ' Older code, reads a file and pulls out the required record. This file has CR+LF after each record, and the records are a fixed length in each file. all records within a given file are the same length.
        Open GcmdTMKFile For Input As #1
        Randomize
        intRandom = Int((GintRecCount * Rnd) + 1)    ' Generate random value between 1 and TmpRecCount
        ' Loop through file until you get to the TmpRandom Record, then exit FOR NEXT LOOP
        For X = 1 To intRandom
            Line Input #1, strRecord
        Next
        ' Find out the current location of the file.
        tmpLocator = Seek(1) ' I added this line to get the current location.
        Close #1
        strTMKRecord = strRecord
    
        ' **Need help with the following, please**
        ' I am adding this code. if the strTMKRecord starts with a "Z", it has already been used.
        ' Otherwise, I just want to write over the record I just selected with Line Input above.
        ' The following code inserts "ZZZZZZ", but it is in the middle of a record and it adds 10 bytes to the file.
        If Mid(strTMKRecord, 1, 1) <> "Z" Then
            ' If we are to this point we have a valid Record, and now need to overwrite the record in the file.
            Open GcmdTMKFile For Binary Access Read Write As #1
            Seek #1, tmpLocator - len(strTMKRecord) ' back up over the record.
            Put #1, , String(Len(strTMKRecord), "Z") & vbNewLine
            Close #1
        End If
    Again, thank you all for all the help.
    kp

  5. #5
    Join Date
    Jul 2008
    Location
    WV
    Posts
    5,362

    Re: WRITE to a file in a specific location

    When a file is opened for output a new file is created so there is no position to read. After you have written to a file that was opened for output you can check the lenght of the file which will tell you where you stopped writing but that is all.

    When you open a file for Input this allows you to read from the file starting at the begining and each bit in order up until you are done. You can keep track of where you are by storing the number of bytes you have pulled during each read remembering of course to account for any CRLF combos if you are doing a line input.

    The sample you showed looks like it is fixed lenght, 4 bytes of data + CRLF for a total of 6 bytes. If all records are to be this size then what you need to do is very simple but if the size varies you are limited as to what you can do. So anyway if every record (or row if you will) is the same length and that length is known then you can use Random Access rather than Input/Output methods.

    For example if your file is 4 bytes per record with crlf for a total of 6 bytes you could search for and replace a value using random access with somethign like this.

    Code:
    Dim FileData As String * 6
    Dim X As Long
    Open TheFile For Random As #1 Len = 6
        Do While X < LOF(1) / 6
            Get #1, X, FileData
            If Mid(FileData, 1, 4) = SearchString Then
               FileData = "XXXX" & vbCrLf
                Put #1, X, FileData
                Exit Do
            End If
            X = X + 1
        Loop
    Close #1
    Note this is freehand code and has been a while since I had a need to do this type of file access so there may be a mistake or 2 in there but should give the basic idea.

    ETA: As you can see this method would be much faster than searching a file then recreating the entire file especially if the search item is near the begining of the file.
    The code above will read only until it finds the match then will replace the value and close the file without reading any more plus it will only be writing 6 bytes rather than the entire file. If the file were sorted then you could add additional code to speed up the search but if unsorted you pretty much have to read from the beging one row at a time until you find your match.

    Of course if there could be more than one matching record you would have to remove the exit do statement so the code would continue to search to the end of the file for additional matches.
    Last edited by DataMiser; December 23rd, 2011 at 02:50 AM.
    Always use [code][/code] tags when posting code.

  6. #6
    Join Date
    Jun 2011
    Posts
    14

    Re: WRITE to a file in a specific location - ONE LAST WRINKLE

    Everyone has been a great help here, and thank you very much.

    Based on the help, I now have this working. However, there is a new wrinkle that I need help working through.

    There is a 'header' record in the file, I did not account for in my previous question.

    The following code that was provided works great without the header. Can someone tell me how to account for this header? I tried starting with X=2, etc. but as the more advanced users here know, that simply advanced the record pointing to the next 9 characters in the file.

    Ideally, I want to just disregard the top line. That is, start reading the file after the first CR+LF. The Header IS variable in length.

    Any help is greatly appreciated. If I can figure that out, all the records are fixed length and this will work GREAT!

    Thanks again in advance for all the help.
    kp

    Code:
    Private Sub Command2_Click()
    Dim FileData As String * 9
    Dim X As Long
    Dim tmpFile As String
    tmpFile = App.Path & "\test32.txt"
    Open tmpFile For Random As #1 Len = 9
    strRecord = "8001426"
        X = 1
        Do While X < LOF(1) / 9
            Get #1, X, FileData
            If Mid(FileData, 1, 7) = strRecord Then
               FileData = "ZZZZZZZ" & vbCrLf
               Put #1, X, FileData
               Exit Do
            End If
            X = X + 1
        Loop
    Close #1
    End Sub
    Example TEST32.TXT
    Code:
    6 0 6 9 1 4 2 1 0 0 
    1001162
    2001163
    3001164
    4001165
    5001168
    6001261
    7001263
    9001265
    0001316
    1001326
    2001361
    3001362
    4001363
    5001364
    6001365
    7001416
    8001426
    9001436
    0001461
    1001462
    2001463
    3001464
    4001465
    Last edited by kpierce; December 25th, 2011 at 03:28 PM.

  7. #7
    Join Date
    Jan 2006
    Location
    Fox Lake, IL
    Posts
    15,007

    Re: WRITE to a file in a specific location

    Other approach, use TWO files, read one, and write the other.
    You can easily split a file based on CR/LF, and eliminate the header.

    Binary mode is not the best way to 'SKIN A CAT' (search for that)
    David

    CodeGuru Article: Bound Controls are Evil-VB6
    2013 Samples: MS CODE Samples

    CodeGuru Reviewer
    2006 Dell CSP
    2006, 2007 & 2008 MVP Visual Basic
    If your question has been answered satisfactorily, and it has been helpful, then, please, Rate this Post!

  8. #8
    Join Date
    Jul 2008
    Location
    WV
    Posts
    5,362

    Re: WRITE to a file in a specific location

    To the best of my knowledge random access works only when all records ar eof the same size. If works extremely well when you know the record number you need to access. For searching a non sorted file without an index it is no better than using line input. For writing it is up there near the top as you only need to write a few bytes but must know the record number.

    You could as suggested above read the file into memory and split it on the CRLF to get each line into an array element. You could then check the length of the first line, search the array then calculate the byte position within the original file and use binary access to write to the correct location. In some cases this would be slower [ such as if the item is within the first few records of a very large file ] in other cases it could be a lot faster [ record is near the end of a very large file ] and in some cases you may get a memory error [ file is to large to process this way ] The latter could be avoided by reading the file in chunks rather than trying to load the entire file at once.

    The real question is why search a text file and replace a value like this, would be much better to use a database engine if possible.

    If the entire file must be loaded and resaved you could just load it, call the replace() function then save.

    The bottom line though is if you have records that are only 4-9 bytes in size that result in a 40+ meg text file and these records must be changed on a regular basis a text file is the worst way I could think of to handle it.
    Always use [code][/code] tags when posting code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured