6.1 Introduction
A stream is a sequence of bytes. A byte is 8 bits. The Stream class and its subclasses
provide a generic view of data sources and repositories, isolating the programmer
from the specific details of the operating system and underlying devices. Streams
involve the following three operations:
1) Streams can be read from. Reading is the transfer of data from a stream into a
data structure, such as an array of bytes.
2) Streams can be written to. Writing is the transfer of data from a data structure
into a stream.
3) Streams can support seeking. Seeking is the query and modifying of the current
position within a stream.
6.2 Binary File Manipulations
System.IO.BinaryWriter and System.IO.BinaryReader can be used for writing
and reading primitive data types
byte, short, int, long, float, double, bool, char
and also the data type string and StringBuilder to a stream (binary file manipulation).
83
84 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
// BinaryIO1.cs
using System;
using System.IO;
using System.Text;
class BinaryIO1
{
private static void WriteData(int i,double d,char c,bool b)
{
Stream s = File.OpenWrite("info.dat");
BinaryWriter bw = new BinaryWriter(s);
bw.Write(i);
bw.Write(d);
bw.Write(c);
bw.Write(b);
bw.Close();
s.Close();
}
private static void ReadData()
{
Stream s = File.OpenRead("info.dat");
BinaryReader br = new BinaryReader(s);
int i = br.ReadInt32();
double d = br.ReadDouble();
char c = br.ReadChar();
bool b = br.ReadBoolean();
br.Close();
s.Close();
Console.WriteLine("{0},{1},{2},{3}",i,d,c,b);
}
public static void Main(string[] args)
{
WriteData(12345,3.14159,’y’,true);
ReadData();
}
}
// BinaryIO2.cs
using System;
using System.IO;
using System.Text;
6.3. TEXT FILE MANIPULATION 85
class BinaryIO2
{
private static void WriteData(string t,StringBuilder sb)
{
Stream s = File.OpenWrite("info.dat");
BinaryWriter bw = new BinaryWriter(s);
// write length-prefixed string
bw.Write(t);
bw.Write(sb.ToString());
bw.Close();
s.Close();
}
private static void ReadData()
{
Stream s = File.OpenRead("info.dat");
BinaryReader br = new BinaryReader(s);
string t = br.ReadString();
string sb = br.ReadString();
br.Close();
s.Close();
Console.WriteLine("{0},{1}",t,sb);
}
public static void Main(string[] args)
{
StringBuilder sb = new StringBuilder("Hello World!");
WriteData("Hello Egoli",sb);
ReadData();
}
}
6.3 Text File Manipulation
Reading a text file. The class FileStream is useful for reading and writing files on
a file system, as well as other file-related operating system handles (including pipes,
standard input, standard output, and so on). FileStream buffers input and output
for better performance. The FileStrean class can open a file in one of two modes,
either synchronously or asynchronously, with signigicant performance consequences
for the synchronous methods (FileStream.Read and FileStream.Write) and the
asynchronous methods FileStream.BeginRead and FileStream.BeginWrite). Both
sets of methods will work in either mode; however, the mode will affect the performance
of these methods. FileStream defaults to opening files synchronously, but
86 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
provides a constructor to open files asynchronously. FileStream objects support
random access to files using the FileStream.Seek method. The Seek method allows
the read/write position to be moved to any position within the file. This is
done with byte offset reference point parameters. The byte offset is relative to the
seek reference point, which can be the beginning, the current position, or the end
of the underlying file, as represented by the three properties of the SeekOrigin class.
We convert the array of bytes into an ASCII text for displaying it on the console.
// readfile.cs
using System;
using System.IO;
using System.Text; // for encoding
class ReadFile
{
public static void Main(string[] args)
{
Stream s = new FileStream(args[0],FileMode.Open);
int size = (int) s.Length;
byte[] buffer = new byte[size];
s.Read(buffer,0,buffer.Length);
s.Close();
string text = Encoding.ASCII.GetString(buffer);
Console.WriteLine(text);
}
}
Writing to a file (text mode). We append the text provided by the line
string text = "all the good men and women" + "\r\n";
to the file provided by args[0].
// writefile.cs
using System;
using System.IO;
using System.Text; // for encoding
class WriteFile
{
public static void Main(string[] args)
{
Stream s = new FileStream(args[0],FileMode.Append,FileAccess.Write);
6.3. TEXT FILE MANIPULATION 87
string text = "all the good men and women" + "\r\n"; // append end
// of line characters
byte[] buffer = Encoding.ASCII.GetBytes(text);
s.Write(buffer,0,buffer.Length);
s.Close(); // also flushes the stream
}
}
Writing the date and time into a file using the DateTime class..
// placeorder.cs
using System;
using System.IO;
class PlaceOrder
{
public static void Main(string[] args)
{
DateTime dt = DateTime.Now;
string today = dt.ToString("dd-MMM-yyyy");
string record = today + "
" + String.Join("
",args);
StreamWriter sw = new StreamWriter("order.txt",true);
sw.WriteLine(record);
sw.Close();
}
}
The useful classes in reading/writing text files are: StreamReader and StreamWriter.
Given the file datain.txt with the two lines
Green 4750 3000.40
Bakley 3451 2800.50
the following program reads the file line by line and displays it on the Console and
also writes it to the output file dataout.txt.
// Filemanipulation.cs
using System;
using System.IO;
class FileManipulation
{
static void Main(string[] args)
{
88 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
FileInfo fr = new FileInfo(@"c:\csharp\datain.txt");
StreamReader reader = fr.OpenText();
string sline;
string[] substrings;
char[] separators = { ’ ’,’,’,’\t’ };
string name;
int ID;
float gpa;
StreamWriter writer =
new StreamWriter(@"c:\csharp\dataout.txt",false);
sline = reader.ReadLine();
while(sline != null)
{
substrings = sline.Split(separators,3);
name = substrings[0];
ID = int.Parse(substrings[1]);
gpa = float.Parse(substrings[2]);
Console.WriteLine("{0} {1} {2}",name,ID,gpa);
writer.WriteLine("{0} {1} {2}",name,ID,gpa);
sline = reader.ReadLine();
}
writer.Flush();
writer.Close();
}
}
6.4 Byte by Byte Manipulation
For reading and writing bytes we use the methods ReadByte() and WriteByte().
The type conversion to char is necessary in the following program. What happens
if we remove (char) ?
// BytebyByte.cs
using System;
using System.IO;
public class BytebyByte
{
public static void Main(string[] args)
{
FileStream s = new FileStream(args[0],FileMode.Open,FileAccess.Read,
FileShare.Read);
BufferedStream bs = new BufferedStream(s);
while(bs.Length > bs.Position)
6.4. BYTE BY BYTE MANIPULATION 89
{
Console.Write((char) bs.ReadByte()); }
}
bs.Close();
s.Close();
}
In the following example we copy byte by byte a file into another file.
// TestFile.cs
using System;
using System.IO;
class TestFile
{
static void Copy(string from,string to,int pos)
{
try
{
FileStream sin = new FileStream(from,FileMode.Open);
FileStream sout = new FileStream(to,FileMode.Create);
sin.Seek(pos,SeekOrigin.Begin);
int ch = sin.ReadByte();
while(ch >= 0)
{
sout.WriteByte((byte) ch); // type conversion
ch = sin.ReadByte();
}
sin.Close();
sout.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine("--file {0} not found",e.FileName);
}
}
public static void Main(string[] arg)
{
Copy(arg[0],arg[1],0);
}
}
90 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
In the next program we count the number of curly brackets in a file.
// Oops1.cs
using System;
using System.IO;
class Oops
{
public static void Main()
{
char cl = ’{’;
int countcl = 0;
char cr = ’}’;
int countcr = 0;
FileStream fin = new FileStream("data.dat",FileMode.Open,FileAccess.Read);
BufferedStream bs = new BufferedStream(fin);
while(bs.Length > bs.Position)
{
char ch = (char) bs.ReadByte();
if(ch == cl) countcl++;
if(ch == cr) countcr++;
} // end while
fin.Close();
Console.WriteLine("countcl = " + countcl);
Console.WriteLine("countcr = " + countcr);
} // end Main
}
Exercise. Extend the program so that it also counts the number of rectangular
brackets (left and right) and parentheses (left and right).
6.5 Object Serialization
Often we want to store a complete object in a stream. This is achieved by a process
called object serialization. By serialization we mean converting an object, or a
connected graph of objects (a set of objects with some set of references to each
other), stored within memory into a linear sequence of bytes. This string of bytes
contains all of the information that was held in the object started with.
// employee.cs
using System;
6.5. OBJECT SERIALIZATION 91
using System.Runtime.Serialization;
[Serializable]
public class Employee
{
public string Name;
public string Job;
public double Salary;
public Employee(string name,string job,double salary)
{
Name = name;
Job = job;
Salary = salary;
}
public Employee() { }
// we override the ToString() method of System.Object.
// This method is invoked whenever an Employee object
// is to be converted to a string
public override string ToString()
{
return String.Format("{0} is a {1} and earns {2}",Name,Job,Salary);
}
} // end class Employee end file
In the following program we apply now object serialization to Employee.
// binsertest1.cs
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
class BinarySerializatioTest1
{
static BinaryFormatter bf = new BinaryFormatter();
private static void WriteEmployee(Employee emp)
{
Stream s = File.OpenWrite("emp.bin");
bf.Serialize(s,emp);
s.Close();
}
92 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
private static void ReadEmployee()
{
Stream s = File.OpenRead("emp.bin");
Employee emp = (Employee) bf.Deserialize(s);
s.Close();
Console.WriteLine(emp); // displays emp.ToString()
}
public static void Main(string[] args)
{
Employee emp = new Employee("Jack","Clerk",44000);
WriteEmployee(emp);
ReadEmployee();
}
}
If we have more than one employee, i.e. an array we extend the program binsertest1.cs
as follows
// serialization.cs
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
class Program
{
// declare binary formatter to read/write serialized text from file
static BinaryFormatter bf = new BinaryFormatter();
static void Main(string[] args)
{
// declare array to hold employee objects
Employee[] employees = new Employee[2];
// create first and second emplyee object in the array
employees[0] = new Employee("John Miller","Salesman",15000);
employees[1] = new Employee("Jack White","Manager",16000);
// serialize employee list to file
Serialize(employees);
// derserialize employee list
DeSerialize();
6.6. XML DOCUMENTS 93
}
static void Serialize(Employee[] employees)
{
// serialize to file
Stream stream = File.OpenWrite("employees.bin");
bf.Serialize(stream,employees);
stream.Close();
Console.WriteLine("Employee list has been serialized to file");
Console.WriteLine();
}
static void DeSerialize()
{
Console.WriteLine("Reading employee list from file");
Console.WriteLine();
// deserialize from file
Stream stream = File.OpenRead("employees.bin");
Employee[] emps = (Employee[])bf.Deserialize(stream);
stream.Close();
// loop through the array and display each employee
foreach(Employee e in emps) Console.WriteLine(e);
Console.WriteLine();
}
}
6.6 XML Documents
The .NET framework provides an XML parser for reading and modifying XML documents.
Given below is the file emp.xml containing information (id,name, job,salary)
about employees. There are five employees.
94 CHAPTER 6. STREAMS AND FILE MANIPULATIONS
The program listemp.cs displays id, and salary of each employee in the file
emp.xml.
// listemp.cs
using System;
using System.Xml;
class ListEmployees
{
public static void Main()
{
XmlDocument doc = new XmlDocument();
// load employee.xml in XmlDocument
doc.Load("emp.xml");
// obtain a list of all employee element
XmlNodeList list = doc.GetElementsByTagName("employee");
foreach(XmlNode emp in list)
{
// obtain value of id attribute of the employee tag
string id = emp.Attributes["id"].Value;
// obtain value of salary subtag of the employee tag
string sal = emp["salary"].FirstChild.Value;
Console.WriteLine("{0}\t{1}",id,sal);
}
}
}
6.6. XML DOCUMENTS 95
The program addemp.cs takes informations from the command line (id, name, job,
salary) and makes a new entry in the file emp.xml.
// addemp.cs
using System;
using System.Xml;
class AddEmployee
{
public static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.Load("emp.xml");
// create a new employee element and value of its attribute
XmlElement emp = doc.CreateElement("employee");
emp.SetAttribute("id",args[0]);
// create a name tag and st its value
XmlNode name = doc.CreateNode("element","name","");
name.InnerText = args[1];
// make name tag a subtag of newly created employee tag
emp.AppendChild(name);
XmlNode job = doc.CreateNode("element","job","");
job.InnerText = args[2];
emp.AppendChild(job);
XmlNode sal = doc.CreateNode("element","salary","");
sal.InnerText = args[3];
emp.AppendChild(sal);
// add the newly created employee tag to the root (employees) tag
doc.DocumentElement.AppendChild(emp);
// save the modified document
doc.Save("emp.xml");
}
}
We execute the program with (for example)
addemp 105 willi president 50000
No comments:
Post a Comment