Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file
Reading/Writing objects to file Reading/Writing objects to file
Reading/Writing objects to file
Go Back  Xtreme Visual Basic Talk > > > Reading/Writing objects to file


Reply
 
Thread Tools Display Modes
  #1  
Old 07-05-2009, 11:30 PM
aeronet aeronet is offline
Newcomer
 
Join Date: Jun 2009
Posts: 5
Default Reading/Writing objects to file


So I need to write out an object to a text file as well as read in objects from text files. How do I accomplish this? This is the code i've used to read and write just simple lines of text. Is there a small modification to this or just a different function i use to read in an entire object?

Code:
Dim path As String
path = "Security.txt"
FileOpen(1, path, OpenMode.Input, OpenAccess.Read)
Do While Not EOF(1)
   Text = LineInput(1)
   lboxUsers.Items.Add(Text)
   'Do other stuff
Loop
FileClose(1)
Thank you!
Reply With Quote
  #2  
Old 07-06-2009, 01:22 PM
AtmaWeapon's Avatar
AtmaWeaponReading/Writing objects to file AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I'd start by reading the File I/O tutorial. Your code is using VB6 compatibility File I/O methods, and many .NET programmers are not familiar with these methods. I can get the general idea of what you're doing, but I don't know what happens in various error situations.

You don't necessarily need to use file I/O methods. .NET has a serialization framework that's good for certain scenarios where you want to save and load data. There's a lot to be said about serialization, but if you're just looking for quick and easy solution all you have to worry about is binary serialization accessible from System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.

To use .NET serialization, you either have to implement the ISerializable interface or mark your class with SerializableAttribute. I usually use the attribute; I believe interface implementation is for more advanced scenarios. Here's a simple class that's ready for serialization:
Code:
<Serializable()> _
Public Class Person

    Private _birthdate As DateTime
    Private _name As String

    Public Sub New()
        _name = ""
    End Sub

    Public Property Birthdate() As DateTime
        Get
            Return _birthdate
        End Get
        Set(ByVal value As DateTime)
            _birthdate = value
        End Set
    End Property

    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

End Class
Here's code that creates a person, writes it to a file, loads it, then prints a comparison of the two people:
Code:
Dim p As New Person() With {.Birthdate = DateTime.Now.AddYears(-15), .Name = "Sam"}
Dim formatter As New BinaryFormatter()

Using output As New FileStream("data.dat", FileMode.Create)
    formatter.Serialize(output, p)
End Using

Dim read As Person
Using input As New FileStream("data.dat", FileMode.Open)
    read = CType(formatter.Deserialize(input), Person)
End Using

Console.WriteLine("{0,-10}{1,-25}", "Name", "Birthday")
Console.WriteLine(New String("-"c, 50))
Console.WriteLine("{0,-10}{1,-25}", p.Name, p.Birthdate)
Console.WriteLine("{0,-10}{1,-25}", read.Name, read.Birthdate)
Note that this makes a binary file; if you want to use text files the only built-in option is System.Xml.Serialization.XmlSerializer which works similarly to BinaryFormatter. You could implement your own formatter for a text format, but properly implementing those interfaces is a pain in the butt.

When I need to use text serialization but don't want the .NET serialization I'm starting to like a certain pattern. I define a separate class that can read/write the type I want to serialize. Here's what the public interface would look like for the Person class:
Code:
Public Class PersonFileIo
    Public Function Read(ByVal path as String) As Person()
    Public Sub Write(ByVal path As String, ByVal person As Person)
    Public Sub Write(ByVal path As String, ByVal people() As Person)
End Class
I tend to use XML as my backing store rather than a custom text format, mainly because it means I don't have to bother writing a parser. Using a separate class for this means I can do a custom text format, XML, or both. There's some other benefits, but that's not the topic of this post.

So your choices are basically binary serialization, XML serialization, or your own custom serialization.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #3  
Old 07-06-2009, 01:47 PM
darkforcesjedi's Avatar
darkforcesjediReading/Writing objects to file darkforcesjedi is offline
Trust me, I'm an

* Expert *
 
Join Date: Apr 2001
Location: In ur base, pwnin d00dz
Posts: 1,964
Default

Why the separate ("PersonFileIo") class? What's the advantage over giving the "Person" class its own Save() and Load() methods? Unless you have a mess of Save()/Load() overloads cluttering up the Person class, I don't see the point.

(In case you couldn't tell I tend to give my classes Save() and Load() methods.)
__________________
To err is human; to debug, divine.
Reply With Quote
  #4  
Old 07-08-2009, 11:07 AM
AtmaWeapon's Avatar
AtmaWeaponReading/Writing objects to file AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I took a while to answer this because I wanted it to be short. It's still long, but it's way better than it started out.

The summary answer with no explanation is "because I wanted to." For the majority of the cases, it's just as easy to put a Save() and Load() method on the object itself. I'm not going to say it's inherently bad or good without a lot of explanation of my views, and I think in most cases you won't run into the things that motivated my decision.

Now for the longer answer. The summary answer is "because it's a good idea." The Single Responsibility Principle is one of the fundamentals of OOD and put simply it states that each class should have one and only one responsibility. Person starts out with the responsibility, "Contain the data that represents a person in this domain." When you add Save() and Load(), you end up with, "Contain the data that represents a person in this domain and provide the ability to persist a person to a file." That's two responsibilities. For smaller applications, this doesn't matter as much because you may know that you'll only ever want to persist a person to a file and it's more convenient to have these methods on the object. SRP doesn't make sense on the small scale because it seems to increase complexity. Let's get more complex and see how it fights complexity in a large application.

Let's say we're making a sprawling enterprise application and we're still using the Person class. The application needs to be able to retrieve and save a Person from the company database. Sometimes, information about a person needs to be sent through a web service so it needs to handle XML that represents a person. Often, a person needs to be sent to a legacy mainframe application that expects a proprietary binary format. Let's look at the Person API with all of this functionality:
Code:
Public Class Person
    Public Property Birthday As DateTime
    Public Property Id As Integer
    Public Property Name As String
    
    Public Sub New()
    
    Public Shared Function LoadFromBinary(ByVal bytes() As Byte) As Person
    Public Shared Function LoadFromDatabase(ByVal id As Integer) As Person
    Public Shared Function LoadFromXml(ByVal xml As String) As Person
    Public Sub SaveToBinary() As Byte()
    Public Sub SaveToDatabase()    
    Public Function SaveToXml() As String
End Class
Hmm... now our responsibilities are "Represent a person in the application domain and be able to persist the person to a database, binary format, and XML." This is getting out of hand. Worse, the database persistence requires that database settings be available to the class: now a Person needs to know how to talk to the database, which means there's some properties missing and an extra responsibility. Also, this is just the public methods; it's likely LoadFromBinary() will require several private methods like ConvertBirthdayFromBinary(). Each of these complicates the job of explaining what Person does and makes testing the class involve more effort. The following list enumerates all of the reasons why you might need to modify the Person class:
  • New information about people needs to be stored.
  • The database changes (database type, connection string, etc.)
  • The binary format changes
  • The XML format changes
Hmm, that means we're going to be working on Person a lot. What's it take to add a new file format? We have to add new methods to Person. If this format requires more information (like the database format), we might end up adding new properties to Person. If these properties must be set, we'll need a new constructor and we'll have to hunt down every place a Person is used to update it. There are ways around that, but research indicates that once you start using a certain pattern it's less likely you'll deviate from it. Each new format involves a host of private methods for conversion. This 3-property, 6-method class looks easy to use on the surface, but under the hood I bet the implementation would involve more like 20 methods.

What if instead of this, we had a group of classes?
Code:
Public Class Person
    Public Property Birthday As DateTime
    Public Property Id As Integer
    Public Property Name As String
    
    Public Sub New()
End Class

Public Module PersonBinaryIo
    Public Function Load(ByVal bytes() As Byte) As Person
    Public Sub Save(ByVal person As Person) As Byte()
End Module

Public Module PersonDatabaseIo
    Public Function Load(ByVal id As Integer) As Person
    Public Sub Save(ByVal person As Person)    
End Module

Public Module PersonFileIo
    Public Function Load(ByVal path As String) As Person
    Public Sub Save(ByVal path As String, ByVal person As Person)
End Module
Now we have 4 classes, each with simple responsibilities ("represent a person", "persist a person to a binary format", etc.) There *is* a strong coupling between these classes: any time Person's properties change you might need to update these other classes, but this is no different than if the methods were part of Person. Also important is Person no longer needs to know about the database; PersonDatabaseIo is responsible for that information (and probably needs some properties for it.) If the mainframe is phased out and you don't need the binary format anymore, you can remove the PersonBinaryIo class without too much fuss; it's probably coupled with other classes that do binary I/O and it will be easy to remove it as those classes are removed. Compare this to removing the binary I/O from Person once integrated; you'll have to remove the extra properties and private methods and any logic that supports them.

Separating the task of "perform I/O" from the task of "represent this concept" pares Person down to a 3-property class with no logic. Let's compare what we have to manage in either case. With the "all in one" approach, Person has 3 properties that relate to a person, a handful of properties that relate to database I/O, and at least a dozen methods related to various I/O tasks. With the split approach, you have a 3-property Person class. PersonBinaryIo has 4 or 5 methods related to binary I/O. PersonDatabaseIo has a a handful of properties that relate to database I/O and 2 methods for the I/O. PersonFileIo has 2 methods for file I/O. Which one sounds easier to explain to a newbie on the project?

As I initially stated, this isn't something you *have* to do for every project. It only reaps a large benefit on projects that require a lot of functionality. I'm starting to do it on all projects, though, because I don't feel like doing it sometimes and not others.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #5  
Old 07-13-2009, 05:03 PM
darkforcesjedi's Avatar
darkforcesjediReading/Writing objects to file darkforcesjedi is offline
Trust me, I'm an

* Expert *
 
Join Date: Apr 2001
Location: In ur base, pwnin d00dz
Posts: 1,964
Default

That makes a lot of sense. I have never worked on applications of that scale. Necessity breeds invention I guess.
__________________
To err is human; to debug, divine.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file Reading/Writing objects to file
Reading/Writing objects to file
Reading/Writing objects to file
 
Reading/Writing objects to file
Reading/Writing objects to file
 
-->