2cpp17 - file io

28
STREAM BASED I/O Michael Heron

Upload: michael-heron

Post on 01-Nov-2014

77 views

Category:

Software


0 download

DESCRIPTION

This is an intermediate conversion course for C++, suitable for second year computing students who may have learned Java or another language in first year.

TRANSCRIPT

Page 1: 2CPP17 - File IO

STREAM BASED I/OMichael Heron

Page 2: 2CPP17 - File IO

Introduction• File I/O in C++ is a relatively straightforward affair.

• For the most part.

• Almost all I/O in C++ is handled via streams.• Like cin and cout

• Random access files also supported.• Not our focus.

• Concept complicated slightly by the presence of objects.• Require a strategy to deal with object representation.

Page 3: 2CPP17 - File IO

Stream I/O• Stream I/O is the simplest kind of I/O

• Read in sequences of bytes from a device.• Write out sequences of bytes to a device

• Broken into two broad categories.• Low level I/O, whereby a set number of bytes are transferred.

• No representation of underlying data formats

• High level I/O• Bytes are grouped into meaningful units

• Such as ints, chars or strings

Page 4: 2CPP17 - File IO

Random Access Files• Sequential files must be read in order.• Random access files permit non-sequential access to

data.• System is considerably more complicated.

• Must have a firm definition of all data attributes.• Issue complicated by the presence of ‘non-fixed length’ data

structures.• Such as strings.

• Must work out the size of a record on disk.

Page 5: 2CPP17 - File IO

Basic File I/O - Output• Straightforward process

• #include <fstream>• Instantiate an ofstream object• Use it like cout• Close in when done:

#include <iostream>#include <fstream>using namespace std;

int main() { ofstream out("blah.txt"); out << "Hello World" << endl; out.close return 0;}

Page 6: 2CPP17 - File IO

Basic File I/O - Input• Same deal

• Use a ifstream object• Use it like cin• Close when done

#include <iostream>#include <fstream>#include <string>

using namespace std;

int main() { ifstream in("blah.txt"); string bleh; in >> bleh; cout << bleh; in.close(); return 0;}

Page 7: 2CPP17 - File IO

Stream Objects• Stream objects must be declared as value objects.

• Not as pointers.• Why?

• Answer due to operator overloading.• Only functions on value objects.

• They work through overloading the << and >> operators.• Thus, value objects only.

Page 8: 2CPP17 - File IO

Stream Objects• The constructor for a stream object can take a second

parameter.• The type of mode for the I/O

• These are defined in the namespace ios:• ofstream out ("blah.txt", ios::app);

• Used for specialising the type of stream.• Above sets an append.

• Others have more esoteric use.

Page 9: 2CPP17 - File IO

So Far, So Good…• Limited opportunities for expression with this system.

• Need more precision on representation of data

• There exist a range of stream manipulators that allow for fine-grained control over stream I/O• dec• hex• octal• setbase

Page 10: 2CPP17 - File IO

Stream Manipulators• These work on simple screen/keyboard I/O and file I/O

• They make use of the Power of Polymorphism

• They are defined in the std namespace.• Inserted into the stream where needed. Acts on the stream from

that point onwards.

#include <iostream>#include <fstream>#include <string>

using namespace std;int main() { cout << oct << 10; return 0;}

Page 11: 2CPP17 - File IO

Stream Manipulators• Some stream manipulators are parameterized

• Like setbase

• These are called parameterized stream manipulators• They get defined in iomanip.h

• When used, they must be provided with the parameter that specialises their behaviour.• setbase takes one of three parameters

• 10, 8 or 16

Page 12: 2CPP17 - File IO

Precision• One of the common things we want to be able to do with

floating point numbers is represent their precision.• Limit the number of decimal places

• This is done using the precision method and the fixed stream manipulator.• Precision takes as its parameter the number of decimal places to

use.

Page 13: 2CPP17 - File IO

Precision#include <iostream>#include <fstream>#include <string>#include <iomanip>

using namespace std;

int main() { float pi = 3.14159265;

cout.precision (5);

cout << fixed << pi; return 0;}

Page 14: 2CPP17 - File IO

Width• We can use the width method to set the maximum field

width of data.• This is not a sticky modifier

• Impacts on the next insertion or extraction only.

• It does not truncate data• You get the full number.

• It does pad data• Useful for strings.

• Defaults to a blank space. Can use the setfill modifier to change the padding character.

Page 15: 2CPP17 - File IO

Other Stream Manipulators• showpoint

• Shows all the trailing zeroes in a floating point number.• Switched off with noshowpoint

• Justification• Used the parameterized setw to set the width of the of the value

• Use left or right to justify• Default is right jutsification

• Research these• Quite a lot to handle various purposes.

Page 16: 2CPP17 - File IO

Object File I/O• This course is about, primarily, object orientation.

• I hope you have noticed that…

• As such, we should talk about how to save objects in C++.• A little bit tricky

• In Java and C#, a process exists called serialization• Writes an object out to a file stream.• Flattens objects into a string of bits

Page 17: 2CPP17 - File IO

Serialization in Javapublic void readFile() { bing = null; try { FileInputStream myFile = new FileInputStream ("bing.dat"); ObjectInputStream in = new ObjectInputStream (myFile); bing = (ExampleClass) in.readObject(); }

catch (Exception ex) { System.out.println ("Error!"); }

}

Page 18: 2CPP17 - File IO

Serialization in C++• C++ has no inherent mechanism for dealing with object

serialization.• We need to Roll Our Own

• Many different ways to do it• Text versus binary• Simple representations

• Good for objects that stand alone

• Complex representations• Encapsulate I/O as part of a class

• Write out the capsule only.

Page 19: 2CPP17 - File IO

Serialization in C++• We will concentrate on the simplest possible

representation here.• For objects that are stand alone.

• Simplest system is to simply write out each value one at a time.• You need to set yourself a file format here.

• When you read the values back in…• Set the appropriate attributes.

• Very simple.• Very limited.

Page 20: 2CPP17 - File IO

Serialization in C++• For more complex representations, more complex

processes are required.• One I like to use is to create save capsules.

• Each class handles only the data it itself is responsible for.• Passes the capsule up the inheritance chain until it reaches the

base class.

• Use a standard data structure for this.• A hash-map is appropriate.

Page 21: 2CPP17 - File IO

Capsule I/O• The process of de-capsuling works in a similar way.

• Pass in a capsule• Extract those elements from the capsule that are relevant• Pass the capsule up the tree.

• Each class must be properly designed to accommodate this.• Representation is robust

• It can handle changes in file structures and inheritance trees.

• Representation is relatively complex• Any break in the chain will break the representation.

Page 22: 2CPP17 - File IO

Capsule I/O• The capsule itself is all we have to save.

• We don’t actually serialize the class, we serialize the hash map.

• Best to use a solid core class for this• Serialization is a fragile process.• Java permits you to just serialize a class.

• Change any of the code, and the saved versions are incompatible.

• Serialization also falls down on very complex objects.• Every part of an object must be serializable.

Page 23: 2CPP17 - File IO

Save Capsule Examplepublic SaveCapsule loadMe (SaveCapsule p) {

p = super.loadMe (p);String room, region;

room = p.getStringValue ("room");region = p.getStringValue ("region");

return p;}

The code that loads the HashMap creates a blank object. Here the HashMap is encapsulated in a class called SaveCapsule.

It then calls loadMe on that object, passing in the save capsule. The first thing that does is pass the save capsule onto the parent for it to load from. This persists up the tree.

Page 24: 2CPP17 - File IO

Serialization• Recommendation for this:

• As simple as you can.• Complexity comes from an inheritance tree. Most complicated and

robust solutions are based around solving this.

• Go with simple flat file representation if possible.• No need to make things more complicated than they have to be.

• Investigate other solutions only as a neccessity.

Page 25: 2CPP17 - File IO

Parsing• We use the word ‘parsing’ to indicate taking a basic data

source and turning it into a more complex representation.• As per your coursework – turn a string into something more

amenable to processing.

• Easy to pull a string in from a file.• Process of turning that into useable data is a parsing exercise.

• Files represent persistence, not structure.• They contain the data, not its context.

Page 26: 2CPP17 - File IO

Reading In A Paragraph• Default >> operator works by using spaces to delimit.

• Pulls out one word at a time.

• More awkward code needed to pull out all strings.• Even more to store them.

• Remember your STL classes here.

• Simplest mechanism to append to a string• In a loop

Page 27: 2CPP17 - File IO

Reading In A Paragraph#include <iostream>#include <fstream>#include <string>#include <iomanip>

using namespace std;

int main() { ifstream in ("blah.txt"); string str;

in >> str;

while (in != NULL) { cout << str << " "; in >> str; }

return 0;}

Page 28: 2CPP17 - File IO

Summary• I/O modeled primarily in C++ as stream based I/O

• Works on the same principles as cin and cout

• Various ways to specialise this behaviour• Stream manipulators• Open modes

• Object representation more complex than in other languages.• C++ requires a bespoke implementation of object serialization.