Text Files

Discussion in 'Tutorials' started by Erel, Oct 5, 2007.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Many applications use text files to store textual data, store user settings or many other usages.
    It is pretty simple to work with text files, but still there are some points that you should be aware of.

    The default encoding for text files is UTF8. This allows you to read or write any Unicode character.
    You could choose to use ASCII encoding instead. ASCII encoding supports only the lower values of the ASCII table (0-127).
    Note that UTF8 encoded files will start with a special Unicode marking.
    Most applications recognize this marking and do not show it.
    However, some older applications will show something like ";fe" at the beginning of the text. In such cases use ASCII encoding instead.
    If you write a DOS batch file (on the desktop) then you should use ASCII encoding for that reason.

    As an example we will create a small application with some user data. The user data will be loaded when the application starts (Sub App_Start) and saved when the application ends (Sub Form1_Close).
    The source code file and the settings file are attached to the post.

    [​IMG]

    Saving code:
    Code:
    [SIZE=2][COLOR=#0000ff]Sub [/COLOR][/SIZE][SIZE=2]SaveINI
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  ErrorLabel[/COLOR][/SIZE][SIZE=2](errSaveINI)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  FileOpen[/COLOR][/SIZE][SIZE=2]( c1,[/SIZE][SIZE=2][COLOR=#800000]"TextFiles.ini"[/COLOR][/SIZE][SIZE=2],cWrite)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  FileWrite[/COLOR][/SIZE][SIZE=2](c1,txtFirstName.Text)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  FileWrite[/COLOR][/SIZE][SIZE=2](c1,txtLastName.Text)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  FileWrite[/COLOR][/SIZE][SIZE=2](c1,chkValidAccount.Checked) [/SIZE][SIZE=2][COLOR=#008000]'writing a boolean value.
    [/COLOR][/SIZE][SIZE=
    2][COLOR=#0000ff]  For[/COLOR][/SIZE][SIZE=2] i = [/SIZE][SIZE=2][COLOR=#800080]0[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] lstData.Count-[/SIZE][SIZE=2][COLOR=#800080]1
    [/COLOR][/SIZE][SIZE=
    2][COLOR=#0000ff]    FileWrite[/COLOR][/SIZE][SIZE=2](c1,lstData.Item(i))
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  Next
    [/COLOR][/SIZE][SIZE=
    2][COLOR=#0000ff]  FileClose[/COLOR][/SIZE][SIZE=2](c1)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  Return[/COLOR][/SIZE][SIZE=2][COLOR=#008000]'If there were no "Return" here, the error message would have shown. 
    [/COLOR][/SIZE][SIZE=
    2]  errSaveINI:
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  Msgbox[/COLOR][/SIZE][SIZE=2]([/SIZE][SIZE=2][COLOR=#800000]"Error writing INI file."[/COLOR][/SIZE][SIZE=2],[/SIZE][SIZE=2][COLOR=#800000]""[/COLOR][/SIZE][SIZE=2],cMsgboxOK,cMsgboxHand)
    [/SIZE][SIZE=
    2][COLOR=#0000ff]  FileClose[/COLOR][/SIZE][SIZE=2](c1)[/SIZE]
    [SIZE=
    2][COLOR=#0000ff]End Sub
    [/COLOR][/SIZE]
    File operations could fail, if for example the file is used by another application.
    We are using ErrorLabel to handle unexpected errors and show a message to the user.

    Now for the real part...
    First we open the file with FileOpen.
    The first parameter is the name that we give to this connection.
    The second parameter is the path and file name.
    In this case the file is located in the same folder of the source code (or compiled executable).
    The third parameter could be cRead, cWrite or cRandom.
    Text files should be opened for reading (cRead) or writing (cWrite), only binary files should use cRandom.
    When using cWrite or cRandom, FileOpen will create a new file if it doesn't exist.
    Text files are usually written one line after another and reading is done in a similar way.
    FileWrite writes a string to the file, each string in a new line.
    FileWrite receives two parameters, the connection name and the value to write.
    Using FileWrite we store the form's data to the file.
    As we've done writing we now close the connection with FileClose.
    Only one connection could be made to a file, so it is important to close the connection when it is no longer required.

    Now for the reading...
    Code:
    [FONT=Courier New][SIZE=2][COLOR=#0000ff]Sub [/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2]LoadINI[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  ErrorLabel[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](errLoadINI)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  If [/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#0000ff]Not[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2]([/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileExist[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2]([/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000]"TextFiles.ini"[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2])) [/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#0000ff]Then [/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#0000ff]Return[/COLOR][/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  FileOpen[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2,[/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000]"TextFiles.ini"[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2],cRead)[/SIZE][/FONT]
    [SIZE=
    2][FONT=Courier New]  txtFirstName.Text = [/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileRead[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [SIZE=
    2][FONT=Courier New]  txtLastName.Text = [/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileRead[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [SIZE=
    2][FONT=Courier New]  chkValidAccount.Checked = [/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileRead[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [SIZE=
    2][FONT=Courier New]  s = [/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileRead[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  Do[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#0000ff]Until[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2] s = EOF [/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#008000]'Read the ListBox items.[/COLOR][/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2]   lstData.Add(s)[/SIZE][/FONT]
    [SIZE=
    2][FONT=Courier New]   s = [/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]FileRead[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  Loop[/COLOR][/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  FileClose[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  Return[/COLOR][/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2]  errLoadINI:[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  Msgbox[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2]([/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000]"Error reading INI file."[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2],[/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000]""[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2],cMsgboxOK,cMsgboxHand)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]  FileClose[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2](c2)[/SIZE][/FONT]
    [
    FONT=Courier New][SIZE=2][COLOR=#0000ff]End Sub[/COLOR][/SIZE][/FONT]
    Again we handle unexpected errors with ErrorLabel.
    First we check if the file exists. If it doesn't exist we exit this sub using Return.
    A new reading connection is created using FileOpen and cRead flag.
    We could have used 'c1' instead of 'c2' as the connection name (c2 is used to prevent confusion between the two parts).
    The settings file is built of several known fields and an unknown number of fields as the ListBox items.
    FileRead reads a single line from the connection.
    Each time the next line will be read.
    In the same order we previously saved the data, we now read the first three known lines.
    The remaining data is now fetched and a new item is added to the ListBox for each line.
    Each line is compared to the EOF constant which symbols the End Of File.
    When the value equals to EOF we know that there are no more items left.
    Another approach would have been to write the number of items before the items.

    FileReadToEnd reads the entire remaining data (unlike FileRead which only reads the next single line).

    Handling binary files could be done with FileGet and FilePut and with the BinaryFile library.
     

    Attached Files:

  2. mick

    mick Member Licensed User

    Saving the second file???

    Hello, Thats a very handy piece of code. Thanks so much for posting it. I was wondering however if anyone knows what to do with saving another file without
    overwriting the first one. In other words, how do you check to see if a file exists and modify the file name if it does. Like test.txt exists so it saves as test2.txt. ect. Thanks, Mick
     
  3. BjornF

    BjornF Active Member Licensed User

    Dear Mick,

    you can use the "FileExist(FileName)" (see the helpfile)

    e.g. in your example

    FileName="test"
    suffix=".txt"

    If FileExist(FileName & Suffix) = true Then FileName=FileName & "2"

    ... and then save the text as FileName & Suffix


    all the best / Björn
     
    Last edited: Jan 3, 2008
  4. mick

    mick Member Licensed User

    Worked Like a Charm

    GREAT! Thanks so much. That worked perfectly. I had a little trouble because
    I left the brackets around (FileName & Suffix), once I removed them like
    If FileExist FileName & Suffix = true Then FileName=FileName & "2"
    Then it worked great. I really appreciate the info. Thanks again, Mick
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    The brackets should be there.
    Also note that FileName is a keyword so don't use it as a variable.
     
  6. mick

    mick Member Licensed User

    One More Step

    Hello again. You are right, I went back and looked and the brackets are there.
    Now I need to wade out a little deeper.:)
    Since I am using the FileWrite method to read the text in some controls and write it to a file, all the files are saved in the program folder of the app. ie
    Program Files\My App.
    How can I modify the file FileWrite to have the files saved in My Documents
    so they are sync't automatically. I saw an example in here that used
    Table1.SaveCSV("\My Documents\file.csv"...) To save a csv file but I can't see how I can use that, especially when I start the routine with "If FileExists" Can I get my app to look in my documents first and then write the file there. Thanks so much, Basic4PPC is the greatest development tool I've ever bought. I love it. Mick
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    Just use "\My Documents\YourFile".
    Code:
    If FileExist ("\My Documents\YourFile"Then
      FileOpen(c1,
    "\My Documents\YourFile",cWrite)
    End If
     
  8. mick

    mick Member Licensed User

    Getting Closer

    Thanks Erel. I'm almost there .I'm still having a bit of trouble because I'm first using
    a variable to declare my file name.
    MyFileName = "TestFile"
    Suffix = ".txt"
    If FileExist(MyFileName & Suffix) = true Then
    MyFileName = "TestFile2"

    That works Great,so when I try to inject the path like


    MyFileName = "My Documents\TestFile"
    Suffix = ".txt"
    If FileExist(MyFileName & Suffix) = true Then
    MyFileName = "My DocumentsTestFile2"

    My error handler grabs it.
    I Feel like such a pest here. I really do appreciate the amazing help I get here.
    Thanks again Mick.
     
  9. specci48

    specci48 Well-Known Member Licensed User

    Is this missing \ a typo in you post or even in your code?

    specci48
     
  10. AppsByAaron

    AppsByAaron New Member Licensed User

    not working for me :(

    I copied and pasted the code then tweaked it for my fields. I get an error when trying to run the program:

    Error compiling program.
    Error description: lstdata is not a known control or object.

    Did I miss something? I can paste all my code (for this Sub) if you like.

    Thanks.
     
  11. specci48

    specci48 Well-Known Member Licensed User

    Hi AppsByAaron

    please look at the sample above (TextFiles.zip).
    LstData is a listbox on form1.


    specci48
     
  12. AppsByAaron

    AppsByAaron New Member Licensed User

    nevermind. I'm an idiot. Got it all figured out.
     
  13. KevG

    KevG New Member Licensed User

    Changing text file data

    This has got me up to speed using text files, ta very to you all.

    Using other programs I can change, let's say one line of a data file without overwriting the whole file.

    I'm jiggered if I can fathom out how to do it in B4PPC.

    Any thoughts, about this, most welcome.

    Regards,

    KevG
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    You can open a file in random access mode and change only parts of it. However as text files use Unicode encoding it will be very hard to find the right position.
    I recommend you to open the file, read the lines one by one or everything at once. Edit the text and save it to a new file.
     
  15. KevG

    KevG New Member Licensed User

    Thanks for that Erel,

    Since posting the thread I've come to the same conclusion.
    The Table / database / CSV file option seems to work and does just the job.

    Ta,

    KevG
     
  16. treaki

    treaki New Member

    Hi,

    ugg, this bbcode problem makes the code nearly unreadable. I did some search/replace to make it readable. for everyone who can use it i paste it here whithout the bbcode problems again:

    Saving code: (code Block 1)

    Code:
    Sub SaveINI
      ErrorLabel(errSaveINI)
      FileOpen( c1,
    "TextFiles.ini",cWrite)
      FileWrite(c1,txtFirstName.Text)
      FileWrite(c1,txtLastName.Text)
      FileWrite(c1,chkValidAccount.Checked) 
    'writing a boolean value.
      For i = 0To lstData.Count-1
        FileWrite(c1,lstData.Item(i))
      
    Next
      FileClose(c1)
      
    Return'If there were no "Return" here, the error message would have shown.
      errSaveINI:
      
    Msgbox("Error writing INI file.","",cMsgboxOK,cMsgboxHand)
      FileClose(c1)
    End Sub
    Now for the reading... (code Block 2)

    Code:
    Sub LoadINI
      ErrorLabel(errLoadINI)
      
    If Not(FileExist("TextFiles.ini")) Then Return
      FileOpen(c2,
    "TextFiles.ini",cRead)
      txtFirstName.Text = FileRead(c2)
      txtLastName.Text = FileRead(c2)
      chkValidAccount.Checked = FileRead(c2)
      s = FileRead(c2)
      DoUntil s = EOF 
    'Read the ListBox items.
      lstData.Add(s)
      s = FileRead(c2)
      
    Loop
      FileClose(c2)
      
    Return
      errLoadINI:
      
    Msgbox("Error reading INI file.","",cMsgboxOK,cMsgboxHand)
      FileClose(c2)
    End Sub
    greetings treaki
     
  17. mjcoon

    mjcoon Well-Known Member Licensed User

    I don't think you will be able to resurrect this thread, nearly five years after the previous contribution...

    Mike.
     
Loading...