Streams, Formatters en Serialization in.net (Tutorial gebaseerd op tutorials van Richard Grimes, het MSDN en anderen)

Vergelijkbare documenten
Dergelijke functionaliteit kunnen we zelf ook aan eigen code toevoegen.

Datatypes Een datatype is de sort van van een waarde van een variabele, veel gebruikte datatypes zijn: String, int, Bool, char en double.

Lezen van en schrijven naar het Windows Registry

Een gelinkte lijst in C#

Zelftest Programmeren in Java

File Uploads met standaard ASP.NET

Uitwerking Aanvullend tentamen Imperatief programmeren Woensdag 24 december 2014, uur

Universiteit van Amsterdam FNWI. Voorbeeld van tussentoets Inleiding programmeren

Werken met ActiveX (COM) componenten in.net

Visual Basic.NET. Visual Basic.NET. M. den Besten 0.3 VB. NET

HOGESCHOOL VAN AMSTERDAM Informatica Opleiding. CPP 1 van 10

vbg.vbnet.beginner Omgaan met files en directories binnen Visual Basic.NET

Programmeren in C# Klassen schrijven

INLEIDING... 1 AFSPRAKEN... 2 INHOUDSOPGAVE...

Voorbeeld: Simulatie van bewegende deeltjes

Uitwerking Tweede deeltentamen Imperatief programmeren - versie 1 Vrijdag 21 oktober 2016, uur

Kleine cursus PHP5. Auteur: Raymond Moesker

Teamhandleiding DOMjudge (versie 2.2.0muKP) 31 mei 2008

Informatica. Objectgeörienteerd leren programmeren. Van de theorie met BlueJ tot een spelletje met Greenfoot... Bert Van den Abbeele

Objectgeoriënteerd programmeren in Java 1

Uitwerking Derde deeltentamen Imperatief programmeren Vrijdag 8 november 2013, uur

Vakgroep CW KAHO Sint-Lieven

Labo 1 Programmeren II

Modelleren en Programmeren

In de tweede regel plaatsen we in het gereserveerde stukje geheugen een getal.

Ingebouwde klassen & methodes

Overerving & Polymorfisme

DOMjudge teamhandleiding

Aanvullende toets Gameprogrammeren Woensdag 5 januari 2011, uur

Uitwerking Tweede deeltentamen Mobiel programmeren - versie 1 Vrijdag 2 februari 2018, uur

Tweede deeltentamen Mobiel programmeren - versie 1 Vrijdag 2 februari 2018, uur

Om de libraries te kunnen gebruiken, moet de programmeur (een deel van) zijn programma in C/C++ schrijven.

SQL datadefinitietaal

Programmeren in C# Samenvatting van C#

Hoofdstuk 1: Inleiding. Hoofdstuk 2: Klassen en objecten Datahiding: afschermen van implementatiedetails. Naar de buitenwereld toe enkel interfaces.

Uitwerkingen derde deeltentamen Gameprogrammeren Vrijdag 6 november 2015, uur

Uitwerkingen Tweede deeltentamen Imperatief programmeren Vrijdag 15 oktober 2010, uur

Tentamen Object Georiënteerd Programmeren TI oktober 2014, Afdeling SCT, Faculteit EWI, TU Delft

Project Software Engineering XML parser: Parsen van een xml CD catalogus

Deel 1: Arduino kennismaking. Wat is een microcontroller, structuur van een programma, syntax,

Zelftest Inleiding Programmeren

ASRemote WebService. Via deze webservice kunt u:

NHibernate als ORM oplossing

Uitwerking Aanvullend tentamen Imperatief programmeren Maandag 14 maart 2011, uur

Een typisch programma in C en C++ bestaat uit een aantal onderdelen:

Visual Studio NET Framework 2.0. campinia media vzw

Java spiekbrief. Commentaar. Definitie van een methode. Types. Variabelendeclaratie. Definitie van een klasse. Namen. Definitie van een veld

Online c++ leren programmeren:

SYNTRA-WEST. Initiatiecursus JAVA. Deel

Programmeren in C++ (deel 1)

Java spiekbrief. Commentaar. Definitie van een methode. Types. Variabelendeclaratie. Definitie van een klasse. Namen. Definitie van een veld

Uitwerking Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 6 november 2015, uur

Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 6 november 2015, uur

FUN12. Dictaat C# klassen en collecties versie februari 2015

Tentamen Imperatief Programmeren

Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 11 november 2016, uur

Tentamen Objectgeorienteerd Programmeren TI februari Afdeling ST Faculteit EWI TU Delft

Derde deeltentamen Gameprogrammeren Vrijdag 7 november 2014, uur

Uitwerkingen. Python Assessment

Tentamen Object Georiënteerd Programmeren TI januari 2013, Afdeling SCT, Faculteit EWI, TU Delft

Dit kan gebruikt worden in zowel een ASP.NET web applicatie als een desktop applicatie.

Datastructuren Werkcollege Intro

No part of this book may be reproduced in any form, by print, photoprint, microfilm or any other means without written permission of the publisher.

MSX Computer & Club Magazine nummer 69 - augustus 1994 Arno Dekker. Scanned, ocr ed and converted to PDF by HansO, 2001

Persistentie via bestanden. Bestanden

Java Programma structuur

TENTAMEN Programmeren 1 VOORBEELDUITWERKING

Inleiding Software Engineering! Unit Testing, Contracten, Debugger! 13 Februari 2014!


Modelleren en Programmeren

Programmeren in Java les 3

Programmeren (1) Examen NAAM:

Leren programmeren in C# Deel 2 - Gegevens

Pascal uitgediept Data structuren

Programmeren. Cursus Python

Voorbeeldtentamen Inleiding programmeren (IN1608WI), Oktober 2003, , Technische Universiteit Delft, Faculteit EWI, Afdeling 2.

Tentamen Computersystemen

Maak een pivot uit een Generic.List

Demo document template available on the Rapptorlab website

MVC BASICS 2. Kevin Picalausa

Een unit test is geen integratie test. Niet het hele systeem, maar onderdelen van een systeem worden getest.

DOMjudge teamhandleiding

IMP Uitwerking week 13

VB Magazine Online /08 1 / 6

Tentamen Inleiding Programmeren (IN1608WI), duur van de toets 2 uur Technische Universiteit Delft, Faculteit EWI, Afdeling 2.

Jochen Mariën september 2013

OEFENINGEN PYTHON REEKS 1

slides12.pdf December 14,

Datastructuren en algoritmen

Uitwerking Tweede deeltentamen Mobiel programmeren - versie 1 Vrijdag 3 februari 2017, uur

Java. Basissyllabus. Egon Pas

Tentamen Imperatief en Object-georiënteerd programmeren in Java voor CKI

Programmeren en Wetenschappelijk Rekenen in Python. Wi1205AE I.A.M. Goddijn, Faculteit EWI 29 april 2014

C++ C++ als een verbetering van C. Abstracte datatypen met classes. Constructoren en destructoren. Subklassen. binding van functies

Dynamisch geheugen beheer

VI. Klassen en objecten

Programmeermethoden. Pointers. Walter Kosters. week 10: november kosterswa/pm/

Vraag 1: HashTable [op 2 punten van de 20] Gegeven de header file HashTable.h van een hashtabel die pointers naar strings bijhoudt (in bijlage).

Tutorial 1, Delphi: Geldspraak

Transcriptie:

Streams, Formatters en Serialization in.net (Tutorial gebaseerd op tutorials van Richard Grimes, het MSDN en anderen) In deze tutorial ga ik in op het gebruik van Streams, Formatters en Serialization. We starten met de abstracte klasse Stream, waarop alle concrete streams gebaseerd zijn, maar ik ga eerst over enkele technieken en wat theorie voor ik het daadwerkelijk over enkele concrete stream klassen ga hebben. 1. De namespace System.IO en de abstracte klasse Stream. Om gebruik te maken van streams moeten we een referentie toevoegen naar de namespace System.IO. using System.IO; Deze namespace bevat onder andere de abstracte klasse Stream, dewelke de mogelijkheden definieert die een concrete stream klasse nodig heeft. De Stream klasse heeft properties die bepalen wat je kan doen met een bepaalde stream, informatie omtrent de stream (zoals lengte, huidige positie in de stream, etc.) en methoden om bytes of arrays van bytes te lezen en te schrijven. Volgend voorbeeld demonstreert het gebruik van een Stream object. We verkrijgen een stream (als voorbeeld) via de methoden GetOutputStream en GetInputStream om respectievelijk te schrijven naar en te lezen van een stream. //Bytes schrijven naar een stream Stream output = GetOutputStream(); byte[ ] outbuf = new byte[5]{20,21,22,23,24}; output.write(outbuf, 0, outbuf.length); output.close(); //Bytes lezen van een stream Stream input = GetInputStream(); byte[ ] inbuf = new byte[(int)instr.length]; input.read(inbuf, 0, inbuf.length); input.close(); In bovenstaande code kunnen de streams output en input om het even welk type stream zijn, bvb. een FileStream, een NetworkStream of een ander type stream. (vervolgt)

NOOT (belangrijk!!!): Omdat streams meestal gebufferd werken (bvb. FileStream), is het noodzakelijk de stream te flushen na gebruik. Dat kan via de methode Flush van een stream, maar er wordt ook automatisch een flush uitgevoerd bij het afsluiten van je stream via de methode Close. Het is dus belangrijk dat je na gebruik van een stream de methode Close aanroept (of Flush wanneer je de stream nog wenst te gebruiken). Als je dit niet doet, zal de buffer pas geflushed worden wanneer de garbage collector het object als verwijderbaar detecteert, en verwijdert uit het geheugen, maar dat kan om het even wanneer zijn, en is dus zeker geen good practice. Ook zal het bestand in gebruik blijven totdat de stream gesloten wordt (Close), waardoor het niet toegankelijk is voor verder gebruik (Tenzij anders ingesteld, bij de parameters voor je stream).

2. Bytes? Chars? Strings? Tekst schrijven naar een stream. Bytes, chars en strings zijn natuurlijk niet gelijk aan elkaar (anders zouden deze 3 verschillende datatypes niet bestaan natuurlijk). Byte Æ 1 byte (duh -). Char Æ 2 unicode bytes. StringÆ Is een object (reference type), bevat o.a. een serie unicode characters. Streams schrijven gegevens typisch weg als bytes. We moeten dus een manier hebben om onze chars te converteren naar bytes en onze strings te converteren naar een byte array. Het mag voor zich spreken dat het.net framework deze mogelijkheid aanbiedt. Er is een ASCII Encoding klasse beschikbaar via de System.Text namespace. Using System.Text;... string str = "Hello world"; byte[ ] b = new byte[str.length]; Encoding.ASCII.GetBytes(str.ToCharArray(), 0, str.length, b, 0); Een string object heeft de methode ToCharArray, dewelke een char array teruggeeft met de unicode chars van de string. Een string heeft ook een property Length, waarmee we weten uit hoeveel characters de string bestaat. Via de Encoding.ASCII klasse uit de System.Text namespace kunnen we de character array van een string omzetten naar een byte array, die we dan wel kunnen wegschrijven naar een stream. (Zie MSDN voor de methoden en overloads) Ook het omgekeerde is mogelijk natuurlijk (een byte array omzetten naar een string): byte[ ] buf = new byte[11]{72,101,108,108,111,32,119,111,114,108,100}; string str; str = System.Text.Encoding.ASCII.GetString(buf); String str zal de tekst Hello world bevatten.

3. Readers en Writers Misschien vinden jullie het al wat omslachtig om eerst conversies te moeten doen vooraleer je de gegevens kan wegschrijven Wel, dat is ook zo, maar je moet er rekening mee houden dat ik tot nu toe het lezen en schrijven van gegevens naar een stream, geïnstancieerd van de abstracte klasse Stream demonstreerde. De ontwerpers van het.net framework zorgden er echter wel voor dat er enkele andere klassen beschikbaar zijn, die de mogelijkheid geven om wel rechtstreeks strings en chars (en andere data types) weg te schrijven naar een stream. Deze klassen breiden als het ware de mogelijkheden van het werken met een stream uit. Zo zijn er de klassen BinaryReader, BinaryWriter, StreamReader en StreamWriter. Typisch nemen deze klassen een stream als parameter voor hun constructor, maar je kan bij de StreamReader en StreamWriter klassen ook een bestandspath opgeven als parameter aan de constructor, waarbij dan automatisch de stream gecreëerd wordt (BinaryReader en BinaryWriter nemen enkel een stream als parameter, geen filepath). Omdat ik het pas later in deze tutorial heb over de concrete stream klassen, geef ik hier enkel een codevoorbeeld omtrent de StreamReader en StreamWriter klassen. //Schrijven naar bestand StreamWriter sw = new StreamWriter("test.txt", false, Encoding.ASCII); sw.writeline("hello world"); sw.close(); //Terug lezen van bestand StreamReader sr = new StreamReader("test.txt", Encoding.ASCII); string input = sr.readline(); sr.close(); //Resultaat in messagebox MessageBox.Show( input ); Er zijn verscheidene constructors voor deze 2 klassen, één voor ieder zijn noden -. Bovenstaande demonstratiecode is heel simpel, en zou voor zich moeten spreken. De parameter false voor de StreamWriter constructor zet append op false voor dit object. Er wordt een string geschreven naar het bestand test.txt via een instantie van de klasse StreamWriter, en deze wordt terug uitgelezen via een instantie van de klasse StreamReader. Daarna wordt de gelezen string in een MessageBox weergegeven.

Noot: Via StreamWriter kan je naast strings ook value types (int, double, decimal, ) wegschrijven naar een stream (en via StreamReader terug uitlezen). Kijk hiervoor naar de overloaded methoden Write en Read van deze klassen.

4. Formatters Wat hebben we tot nu toe gezien? We kunnen reeds simpele gegevens (hoofdzakelijk strings en value types) wegschrijven naar en lezen van een stream. Dit is heel bruikbaar voor simpele testjes, of zelfs voor het werken met een log bestand, maar in de praktijk gebeurt het meer dat er objecten worden weggeschreven naar een stream. Eventueel zou je dit kunnen omzeilen via de methode ToString van een object, en bij het terug inlezen van een object zou je een constructor die deze string kan parsen kunnen gebruiken, maar er is een efficiëntere methode. Wat we gaan doen, wordt Object Serialization genoemd (I/O met objecten). Dit gebeurt in samenwerking met een Formatter. Object Serialization serialiseert een object naar een bytestream, en we leerden reeds dat streams gebaseerd zijn op het lezen en schrijven van bytes. Om een klasse serialiseerbaar te maken, moet je de statement [Serializable] voor de klassedefinitie plaatsen. (Als je in de MSDN informatie naleest omtrent verschillende klassen, is meestal ook vermeld of je een bepaalde klasse kan serialiseren). Een voorbeeldklasse Point : [Serializable] public class Point { private double xval; private double yval; [NonSerialized] private double len = 0; public Point(int x, int y) { xval = x; yval = y; } public double x{get{return xval;}} public double y{get{return xval;}} public double Length { get { if (len == 0) len = Math.Sqrt(x*x + y*y); return len; } } }

Door de statement Serializable weet de compiler dat desbetreffende klasse serialiseerbaar is. Let op het field [NonSerialized] private double len = 0;, wegens het statement NonSerialized zal dit field niet opgenomen worden in het geserializeerd object. Deze nonserialized fields gaan een waarde null meekrijgen bij het serializeren, afhankelijk van hun datatype, bijvoorbeeld 0 voor een integer, en null voor een reference. Laat ons nu een demonstreren hoe een object geserializeerd wordt naar een stream (we maken gebruik van bovenstaande klasse Point, stm is de stream voor volgend voorbeeld) : Point p1 = new Point(1, 2); Point p2 = new Point(3, 4); Point p3 = new Point(5, 6); BinaryFormatter bf = new BinaryFormatter(); bf.serialize(stm, p1); bf.serialize(stm, p2); bf.serialize(stm, p3); str.close(); Je kan dus gebruik maken van een BinaryFormatter object, en via zijn methode Serialize kan je je object serializeren op een stream. Omgekeerd is even simpel, je deserializeert de objecten van een stream: Point p4, p5, p6; p4 = (Point)bf.Deserialize(str); p5 = (Point)bf.Deserialize(str); p6 = (Point)bf.Deserialize(str); De methode deserialize creëert een instantie van het geserialiseerde object, waarbij alle geserialiseerde fields geïnitialiseerd worden naar de opgeslagen waarde. De nonserialised fields gaan op hun null waarde ingesteld worden. Noot: De BinaryFormatter krijgt volle toegang tot private fields, waardoor je je daar geen zorgen om hoeft te maken - Fantastisch niet!? Noot: Hoe kan deserialize nu weten welk type klasse hij moet instanciëren? Er wordt naast de objectgegevens ook wat informatie omtrent de klasse van het object weggeschreven. Dit wordt bepaald door de klasse SerializationInfo.

5. Streams Eindelijk ga ik het hebben over streams. Vergis je echter niet, de technieken beschreven bij de vorige hoofdstukjes van deze tutorial zijn heel belangrijk. Je dient die te kennen om correct te werken met streams. De Stream klasse is abstract, nu gaan we het hebben over concrete stream klassen, die afgeleid zijn van de Stream klasse. De manier waarop je een stream aanmaakt verschilt van stream klasse tot stream klasse. Met volgende code kan je bijvoorbeeld een FileStream verkrijgen: File.OpenRead("sourcefile.txt"); Noot: OpenRead is een statische methode van de klasse File, die beschikbaar is van de System.IO namespace. Deze klasse File bevat nog meer van deze heel interessante mogelijkheden, zoals File.Exissts om te checken of een bestand bestaat, enzovoort... Wederom: Zie de MSDN voor meer informatie. In samenwerking met de eerder besproken StreamReader klasse kunnen we als volgt werken: StreamReader input; input = new StreamReader( File.OpenRead("test.txt") ); En om te schrijven naar een bestand : StreamWriter write; write = new StreamWriter( File.OpenWrite("destfile.txt") ); Oefening: Nu zou je het vorige voorbeeld, waarbij we Hello World schrijven naar bestand en nadien terug uitlezen met weergave in een messagebox, zelf moeten kunnen aanpassen zodat die werkt met een FileStream. (vervolgt)

Je weet nu dat sommige methoden je een stream kunnen teruggeven (als return value). Je kan streams natuurlijk ook zelf definiëren. In volgend voorbeeld definiëren we zelf een FileStream om te lezen uit een bestand: FileStream f = new FileStream( test.txt, FileMode.Open, FileAccess.Read, FileShare.Read); Voor de verschillende overloads van de constructors van de stream klassen kijk je best in de MSDN. Verschillende types streams: Ik ga nog even heel kort in op enkele van de belangrijkste stream klassen: FileStream : Gebufferde stream om te lezen van en schrijven naar bestanden. NetworkStream : Ongebufferde stream om gegevens te verzenden tussen meerdere computers op via een netwerk. MemoryStream : Gegevens kunnen opgeslagen worden in het computergeheugen. BufferedStream : Hiermee kan je ongebufferde streams gebufferd laten werken. PS: In de volgende tutorial, namelijk networkstreams, gaan we een pong spelletje maken voor 2 spelers in een netwerk. Hierbij gaan we object serialization gebruiken op een NetworkStream om de positie van de tegenspeler (en het balletje) op het speelveld te communiceren tussen de 2 applicaties. Veel plezier. Kris.