Page 1 of 1

Store user data in one file - how?

Posted: Fri Jul 31, 2009 10:19 am
by PB
Hi all,

My flagship app stores a lot of dynamic user information. Sometimes it's just
one line of text, and other times it's many lines. Currently I store all these as
single plain text files on disk, mainly because I wanted to be able to delete
and edit them manually without running the app. The data stored is always
just plain text like names, file paths, and so on. No binary data.

But now I think I'd prefer to store it all in one local file, to make it portable.
How the heck do I convert all my code to do that? I know nothing about
databases so using MySQL (and such) is a no-no due to lack of time to
learn it.

Do you think using a single INI file with groups is what I should do? From
what I can see from the manual, it looks doable and allows me to store
and delete data dynamically from it. Should I try writing procedures that
emulate the CreateFile and ReadFile commands but that works on an INI
file instead? I think that would make the conversion go quicker than doing
it all from scratch?

Any ideas appreciated. Thanks.

Posted: Fri Jul 31, 2009 10:32 am
by srod
If you wish to retain the ability to manually edit these files then yes a PB preferences file or some kind of CSV file or an XML file would seem logical choices. Even consider using an Excel spreadsheet which you can access either via COMatePLUS or through PB's database library (via ODBC).

Personally, I would consider using an SQLite database. Not directly editable of course; but very convenient and very easy to learn how to use. Would take you about 10 minutes to get to grips with it. :)

Posted: Fri Jul 31, 2009 11:25 am
by Joakim Christiansen
What about a .ini file?
Look under "preference" in the PB help. I think that should be easy to use, here is an example on how I used it in a application:

Code: Select all

OpenPreferences("config.ini")
  PreferenceGroup("GetCategories")
   GetCategory\Unknown     = ReadPreferenceLong("Unknown",1)
   GetCategory\Business    = ReadPreferenceLong("Business",1)
   GetCategory\Cable       = ReadPreferenceLong("Cable",1)
   GetCategory\Children    = ReadPreferenceLong("Children",1)
   GetCategory\Documentary = ReadPreferenceLong("Documentary",1)
   ;...
  
  PreferenceGroup("Misc")
   Settings\RememberWindow = ReadPreferenceLong("RememberWindowSize",1)
   Settings\RememberColumn = ReadPreferenceLong("RememberColumnWidth",1)
   Settings\RememberCountry = ReadPreferenceLong("RememberCountry",1)
   SelectedCountry = ReadPreferenceLong("LastCountry",1)
  
  PreferenceGroup("Column widths")
   Column1Width    = ReadPreferenceLong("Column1",80)
   Column2Width    = ReadPreferenceLong("Column2",70)
   Column3Width    = ReadPreferenceLong("Column3",44)
   Column4Width    = ReadPreferenceLong("Column4",42)
   Column5Width    = ReadPreferenceLong("Column5",180)
ClosePreferences()
Edit: Oh, I see you just edited your post, hehe... (well, at least I didn't notice the part about .ini before)

Posted: Fri Jul 31, 2009 11:50 am
by PB
Not edited. :)

Anyway, what about multiple lines when using INI files? I don't think the
preferences lib supports that?

Posted: Fri Jul 31, 2009 12:13 pm
by srod
Anyway, what about multiple lines when using INI files? I don't think the preferences lib supports that?
Depends on what you mean? If you mean that individual strings may contain EOL characters in order to separate multiple lines of text etc. then you are correct. You would need to add some kind of encoding yourself. Then again this is true for all text based files. I generally save in utf-8 format when doing this but prefix each string with 4 bytes giving the number of bytes in the string. I then use ReadData() to retrieve the string etc. This of course is heading towards some kind of binary file which may not suit your purposes on this occasion.

xml has no problem with multiple lines for each node's text.

Posted: Fri Jul 31, 2009 12:59 pm
by PB
I mean my data will have #CRLF$ in it, so using the preferences lib won't be
able to handle that, because it's one line per item entry. I really don't want
to have to learn MySQL. I'll probably just drop the idea. The app is still
portable anyway -- just copy the folder and not the individual files. ;)

Posted: Fri Jul 31, 2009 1:02 pm
by srod
As I say; there is always XML.

Posted: Fri Jul 31, 2009 8:01 pm
by utopiomania
I use PB preference files, which can easily be edited in Notepad if you need to:

Code: Select all

procedure writePreferences(inFolder.s, name.s)
  #CSIDL_APPDATA = $1A
  ;	XP:     C:\Documents and Settings\username\Application Data*    
  ;	Vista:  C:\Users\username\AppData\Roaming
  if len(inFolder)
    inFolder + "\"
  endIf
  path.s = getPathPart(programFileName())
  type = getDriveType_(left(path, 2))
  if type = 2
    ;removable
    path = path + inFolder
  else
    path = getSpecialFolder(#CSIDL_APPDATA) + inFolder
  endIf
  createDirectory(path)
  if createPreferences(path + name)
    writePreferenceLong("language", lang)
    writePreferenceString("fileExtensions", fileExt)
    writePreferenceLong("deleteFiles", delFiles)
    writePreferenceLong("allUsers", allUsers)
    writePreferenceLong("yearFolder", yearFolder)
    writePreferenceLong("dateFolder", dateFolder)
    closePreferences()
    procedureReturn 1    
  endIf
  procedureReturn 0
endProcedure

procedure readPreferences(inFolder.s, name.s)
  #CSIDL_APPDATA = $1A
  ;	XP:     C:\Documents and Settings\username\Application Data*    
  ;	Vista:  C:\Users\username\AppData\Roaming
  if len(inFolder)
    inFolder + "\"
  endIf
  path.s = getPathPart(programFileName())
  type = getDriveType_(left(path, 2))
  if type = 2
    ;removable
    path = path + inFolder + name
  else
    path = getSpecialFolder(#CSIDL_APPDATA) + inFolder + name
  endIf
  openPreferences(path)
  lang = readPreferenceLong("language", 0)
  tempLang = lang
  fileExt = readPreferenceString("fileExtensions", defaultFileExt)
  delFiles = readPreferenceLong("deleteFiles", 0)
  allUsers = readPreferenceLong("allUsers", 1)
  yearFolder = readPreferenceLong("yearFolder", 1)
  dateFolder = readPreferenceLong("dateFolder", 0)
  closePreferences()
endProcedure

Posted: Fri Jul 31, 2009 9:31 pm
by Edwin Knoppert
Two tips:

1) IStorage interface

2) Sqlite