Code Listings
Chapter 13: Streams and I/O
Basic use of a stream:
using System; using System.IO; class Program { static void Main() { // Create a file called test.txt in the current directory: using (Stream s = new FileStream ("test.txt", FileMode.Create)) { Console.WriteLine (s.CanRead); // true Console.WriteLine (s.CanWrite); // true Console.WriteLine (s.CanSeek); // true s.WriteByte (101); s.WriteByte (102); byte[] block = { 1, 2, 3, 4, 5 }; s.Write (block, 0, block.Length); // Write block of 5 bytes Console.WriteLine (s.Length); // 7 Console.WriteLine (s.Position); // 7 s.Position = 0; // Move back to the start Console.WriteLine (s.ReadByte()); // 101 Console.WriteLine (s.ReadByte()); // 102 // Read from the stream back into the block array: Console.WriteLine (s.Read (block, 0, block.Length)); // 5 // Assuming the last Read returned 5, we'll be at // the end of the file, so Read will now return 0: Console.WriteLine (s.Read (block, 0, block.Length)); // 0 } } }
Reading a 1000 bytes from a stream:
byte[] data = new byte [1000]; // bytesRead will always end up at 1000, unless the stream is // itself smaller in length: int bytesRead = 0; int chunkSize = 1; while (bytesRead < data.Length && chunkSize > 0) bytesRead += chunkSize = s.Read (data, bytesRead, data.Length - bytesRead);
An easier way:
byte[] data = new BinaryReader (s).ReadBytes (1000);
Reading into a MemoryStream:
static MemoryStream ToMemoryStream (Stream input, bool closeInput) { try { // Read and write in byte[] block = new byte [0x1000]; // blocks of 4K. MemoryStream ms = new MemoryStream(); while (true) { int bytesRead = input.Read (block, 0, block.Length); if (bytesRead == 0) return ms; ms.Write (block, 0, bytesRead); } } finally { if (closeInput) input.Close(); } }
Named pipes:
// Server: using (var s = new NamedPipeServerStream ("pipedream") { s.WaitForConnection(); s.WriteByte (100); Console.WriteLine (s.ReadByte()); }
// Client: using (var s = new NamedPipeClientStream ("pipedream")) { s.Connect(); Console.WriteLine (s.ReadByte()); s.WriteByte (200); // Send the value 200 back. }
Message transmission mode:
static byte[] ReadMessage (PipeStream s) { MemoryStream ms = new MemoryStream(); byte[] buffer = new byte [0x1000]; // Read in 4KB blocks do { ms.Write (buffer, 0, s.Read (buffer, 0, buffer.Length)); } while (!s.IsMessageComplete); return ms.ToArray(); }
// Server: using (var s = new NamedPipeServerStream ("pipedream", PipeDirection.InOut, 1, PipeTransmissionMode.Message)) { s.WaitForConnection(); byte[] msg = Encoding.UTF8.GetBytes ("Hello"); s.Write (msg, 0, msg.Length); Console.WriteLine (Encoding.UTF8.GetString (ReadMessage (s))); }
// Client: using (var s = new NamedPipeClientStream ("pipedream")) { s.Connect(); s.ReadMode = PipeTransmissionMode.Message; Console.WriteLine (Encoding.UTF8.GetString (ReadMessage (s))); byte[] msg = Encoding.UTF8.GetBytes ("Hello right back!"); s.Write (msg, 0, msg.Length); }
Anonymous pipes server:
string clientExe = "d:\PipeDemo\ClientDemo.exe"; HandleInheritability inherit = HandleInheritability.Inheritable; using (var tx = new AnonymousPipeServerStream (PipeDirection.Out, inherit)) using (var rx = new AnonymousPipeServerStream (PipeDirection.In, inherit)) { string txID = tx.GetClientHandleAsString(); string rxID = rx.GetClientHandleAsString(); var startInfo = new ProcessStartInfo (clientExe, txID + " " + rxID); startInfo.UseShellExecute = false; // Required for child process Process p = Process.Start (startInfo); tx.DisposeLocalCopyOfClientHandle(); // Release unmanaged rx.DisposeLocalCopyOfClientHandle(); // handle resources. tx.WriteByte (100); Console.WriteLine ("Server received: " + rx.ReadByte()); p.WaitForExit(); }
Anonymous pipes client:
static void Main (string[] args) { string rxID = args[0]; // Note we’re reversing the string txID = args[1]; // receive and transmit roles. using (var rx = new AnonymousPipeClientStream (PipeDirection.In, rxID)) using (var tx = new AnonymousPipeClientStream (PipeDirection.Out, txID)) { Console.WriteLine ("Client received: " + rx.ReadByte()); tx.WriteByte (200); } }
BufferedStream:
// Write 100K to a file: File.WriteAllBytes ("myFile.bin", new byte [100000]); using (FileStream fs = File.OpenRead ("myFile.bin")) using (BufferedStream bs = new BufferedStream (fs, 20000)) //20K buffer { bs.ReadByte(); Console.WriteLine (fs.Position); // 20000 }
StreamReader and StreamWriter:
using (FileStream fs = File.Create ("test.txt")) using (TextWriter writer = new StreamWriter (fs)) { writer.WriteLine ("Line1"); writer.WriteLine ("Line2"); } using (FileStream fs = File.OpenRead ("test.txt")) using (TextReader reader = new StreamReader (fs)) { Console.WriteLine (reader.ReadLine()); // Line1 Console.WriteLine (reader.ReadLine()); // Line2 }
using (TextWriter writer = File.CreateText ("test.txt")) { writer.WriteLine ("Line1"); writer.WriteLine ("Line2"); } using (TextWriter writer = File.AppendText ("test.txt")) writer.WriteLine ("Line3"); using (TextReader reader = File.OpenText ("test.txt")) while (reader.Peek() > -1) Console.WriteLine (reader.ReadLine()); // Line1 // Line2 // Line3
using (TextWriter w = File.CreateText ("data.txt")) { w.WriteLine (123); // Writes "123" w.WriteLine (true); // Writes the word "true" } using (TextReader r = File.OpenText ("data.txt")) { int myInt = int.Parse (r.ReadLine()); // myInt == 123 bool yes = bool.Parse (r.ReadLine()); // yes == true }
Character encodings:
using (TextWriter w = File.CreateText ("but.txt")) // Use default UTF-8 w.WriteLine ("but—"); // encoding. using (Stream s = File.OpenRead ("but.txt")) for (int b; (b = s.ReadByte()) > -1;) Console.WriteLine (b);
using (Stream s = File.Create ("but.txt")) using (TextWriter w = new StreamWriter (s, Encoding.Unicode)) w.WriteLine ("but—"); foreach (byte b in File.ReadAllBytes ("but.txt")) Console.WriteLine (b);
Binary adapaters:
public class Person { public string Name; public int Age; public double Height; public void SaveData (Stream s) { BinaryWriter w = new BinaryWriter (s); w.Write (Name); w.Write (Age); w.Write (Height); w.Flush(); // Ensure the BinaryWriter buffer is cleared. // We won't dispose/close it, so more data } // can to be written to the stream. public void LoadData (Stream s) { BinaryReader r = new BinaryReader (s); Name = r.ReadString(); Age = r.ReadInt32(); Height = r.ReadDouble(); } }
Compressing a directory:
static uint CompressFolder (string folder, bool recursive) { string path = "Win32_Directory.Name='" + folder + "'"; using (ManagementObject dir = new ManagementObject (path)) using (ManagementBaseObject p = dir.GetMethodParameters ("CompressEx")) { p ["Recursive"] = recursive; using (ManagementBaseObject result = dir.InvokeMethod ("CompressEx", p, null)) return (uint) result.Properties ["ReturnValue"].Value; } }
Determining if a volume supports compression & encryption:
using System; using System.IO; using System.Text; using System.Runtime.InteropServices; class SupportsCompressionEncryption { const int SupportsCompression = 0x10; const int SupportsEncryption = 0x20000; [DllImport ("Kernel32.dll", SetLastError = true)] extern static bool GetVolumeInformation (string vol, StringBuilder name, int nameSize, out uint serialNum, out uint maxNameLen, out uint flags, StringBuilder fileSysName, int fileSysNameSize); static void Main() { uint serialNum, maxNameLen, flags; bool ok = GetVolumeInformation (@"C:\", null, 0, out serialNum, out maxNameLen, out flags, null, 0); if (!ok) throw new Exception ("Error: Win32 code=" + Marshal.GetLastWin32Error()); bool canCompress = (flags & SupportsCompression) > 0; bool canEncrypt = (flags & SupportsEncryption) > 0; } }
File security:
using System; using System.IO; using System.Security.AccessControl; using System.Security.Principal; public static void Main() { FileSecurity sec = File.GetAccessControl (@"c:\temp\test.txt"); AuthorizationRuleCollection rules = sec.GetAccessRules (true, true, typeof (NTAccount)); foreach (FileSystemAccessRule rule in rules) { Console.WriteLine (rule.AccessControlType); // Allow or Deny Console.WriteLine (rule.FileSystemRights); // e.g. FullControl Console.WriteLine (rule.IdentityReference.Value); // e.g. MyDomain/Joe } FileSystemAccessRule newRule = new FileSystemAccessRule ("Users", FileSystemRights.ExecuteFile, AccessControlType.Allow); sec.AddAccessRule (newRule); File.SetAccessControl (@"c:\temp\test.txt", sec); }
FileInfo and DirectoryInfo:
FileInfo fi = new FileInfo (@"c:\temp\FileInfo.txt"); Console.WriteLine (fi.Exists); // false using (TextWriter w = fi.CreateText()) w.Write ("Some text"); Console.WriteLine (fi.Exists); // false (still) fi.Refresh(); Console.WriteLine (fi.Exists); // true Console.WriteLine (fi.Name); // FileInfo.txt Console.WriteLine (fi.FullName); // c:\temp\FileInfo.txt Console.WriteLine (fi.DirectoryName); // c:\temp Console.WriteLine (fi.Directory.Name); // temp Console.WriteLine (fi.Extension); // .txt Console.WriteLine (fi.Length); // 9 fi.Encrypt(); fi.Attributes ^= FileAttributes.Hidden; // (Toggle hidden flag) fi.IsReadOnly = true; Console.WriteLine (fi.Attributes); // ReadOnly,Archive,Hidden,Encrypted Console.WriteLine (fi.CreationTime); fi.MoveTo (@"c:\temp\FileInfoX.txt"); DirectoryInfo di = fi.Directory; Console.WriteLine (di.Name); // temp Console.WriteLine (di.FullName); // c:\temp Console.WriteLine (di.Parent.FullName); // c:\ di.CreateSubdirectory ("SubFolder");
Enumerating files and subdirectories:
DirectoryInfo di = new DirectoryInfo (@"e:\photos"); foreach (FileInfo fi in di.GetFiles ("*.jpg")) Console.WriteLine (fi.Name); foreach (DirectoryInfo subDir in di.GetDirectories()) Console.WriteLine (subDir.FullName);
Querying volume information:
DriveInfo c = new DriveInfo ("C"); // Query the C: drive. long totalSize = c.TotalSize; // Size in bytes. long freeBytes = c.TotalFreeSpace; // Ignores disk quotas. long freeToMe = c.AvailableFreeSpace; // Takes quotas into account. foreach (DriveInfo d in DriveInfo.GetDrives()) // All defined drives. { Console.WriteLine (d.Name); // C:\ Console.WriteLine (d.DriveType); // Fixed Console.WriteLine (d.RootDirectory); // C:\ if (d.IsReady) // If the drive is not ready, the following two // properties will throw exceptions: { Console.WriteLine (d.VolumeLabel); // The Sea Drive Console.WriteLine (d.DriveFormat); // NTFS } }
Catching filesystem events:
static void Main() { Watch (@"c:\temp", "*.txt", true); } static void Watch (string path, string filter, bool includeSubDirs) { using (FileSystemWatcher watcher = new FileSystemWatcher (path, filter)) { watcher.Created += FileCreatedChangedDeleted; watcher.Changed += FileCreatedChangedDeleted; watcher.Deleted += FileCreatedChangedDeleted; watcher.Renamed += FileRenamed; watcher.Error += FileError; watcher.IncludeSubdirectories = includeSubDirs; watcher.EnableRaisingEvents = true; Console.WriteLine ("Listening for events - press <enter> to end"); Console.ReadLine(); } // Disposing the FileSystemWatcher stops further events from firing. } static void FileCreatedChangedDeleted (object o, FileSystemEventArgs e) { Console.WriteLine ("File {0} has been {1}", e.FullPath, e.ChangeType); } static void FileRenamed (object o, RenamedEventArgs e) { Console.WriteLine ("Renamed: {0}->{1}", e.OldFullPath, e.FullPath); } static void FileError (object o, ErrorEventArgs e) { Console.WriteLine ("Error: " + e.GetException().Message); }
Compression:
using (Stream s = File.Create ("compressed.bin")) using (Stream ds = new DeflateStream (s, CompressionMode.Compress)) for (byte i = 0; i < 100; i++) ds.WriteByte (i); using (Stream s = File.OpenRead ("compressed.bin")) using (Stream ds = new DeflateStream (s, CompressionMode.Decompress)) for (byte i = 0; i < 100; i++) Console.WriteLine (ds.ReadByte()); // Writes 0 to 99
string[] words = "The quick brown fox jumps over the lazy dog".Split(); Random rand = new Random(); using (Stream s = File.Create ("compressed.bin")) using (Stream ds = new DeflateStream (s, CompressionMode.Compress)) using (TextWriter w = new StreamWriter (ds)) for (int i = 0; i < 1000; i++) w.Write (words [rand.Next (words.Length)] + " "); Console.WriteLine (new FileInfo ("compressed.bin").Length); // 1073 using (Stream s = File.OpenRead ("compressed.bin")) using (Stream ds = new DeflateStream (s, CompressionMode.Decompress)) using (TextReader r = new StreamReader (ds)) Console.Write (r.ReadToEnd()); // Output below:
Compressing in memory, option 1:
byte[] data = new byte[1000]; // We can expect a good compression // ratio from an empty array! MemoryStream ms = new MemoryStream(); using (Stream ds = new DeflateStream (ms, CompressionMode.Compress)) ds.Write (data, 0, data.Length); byte[] compressed = ms.ToArray(); Console.WriteLine (compressed.Length); // 113 // Decompress back to the data array: ms = new MemoryStream (compressed); using (Stream ds = new DeflateStream (ms, CompressionMode.Decompress)) for (int i = 0; i < 1000; i += ds.Read (data, i, 1000 - i));
Compressing in memory, option 2:
byte[] data = new byte[1000]; MemoryStream ms = new MemoryStream(); using (Stream ds = new DeflateStream (ms, CompressionMode.Compress, true)) ds.Write (data, 0, data.Length); Console.WriteLine (ms.Length); // 113 ms.Position = 0; using (Stream ds = new DeflateStream (ms, CompressionMode.Decompress)) for (int i = 0; i < 1000; i += ds.Read (data, i, 1000 - i));
Reading and writing isolated storage:
// IsolatedStorage classes live in System.IO.IsolatedStorage using (IsolatedStorageFile f = IsolatedStorageFile.GetMachineStoreForDomain()) using (var s = new IsolatedStorageFileStream ("hi.txt",FileMode.Create,f)) using (var writer = new StreamWriter (s)) writer.WriteLine ("Hello, World"); // Read it back: using (IsolatedStorageFile f = IsolatedStorageFile.GetMachineStoreForDomain()) using (var s = new IsolatedStorageFileStream ("hi.txt", FileMode.Open, f)) using (var reader = new StreamReader (s)) Console.WriteLine (reader.ReadToEnd()); // Hello, world
Roaming user isolation:
var flags = IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming; using (IsolatedStorageFile f = IsolatedStorageFile.GetStore (flags, null, null)) using (var s = new IsolatedStorageFileStream ("a.txt", FileMode.Create, f)) using (var writer = new StreamWriter (s)) writer.WriteLine ("Hello, World");
Enumerating isolated storage:
using (IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForDomain()) { using (var s = new IsolatedStorageFileStream ("f1.x",FileMode.Create,f)) s.WriteByte (123); using (var s = new IsolatedStorageFileStream ("f2.x",FileMode.Create,f)) s.WriteByte (123); foreach (string s in f.GetFileNames ("*.*")) Console.Write (s + " "); // f1.x f2.x }
Creating and removing subdirectories:
using (IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForDomain()) { f.CreateDirectory ("subfolder"); foreach (string s in f.GetDirectoryNames ("*.*")) Console.WriteLine (s); // subfolder using (var s = new IsolatedStorageFileStream (@"subfolder\sub1.txt", FileMode.Create, f)) s.WriteByte (100); f.DeleteFile (@"subfolder\sub1.txt"); f.DeleteDirectory ("subfolder"); }
Enumerating over other applications' stores:
System.Collections.IEnumerator rator = IsolatedStorageFile.GetEnumerator (IsolatedStorageScope.User); while (rator.MoveNext()) { var isf = (IsolatedStorageFile) rator.Current; Console.WriteLine (isf.AssemblyIdentity); // Strong name or URI Console.WriteLine (isf.CurrentSize); Console.WriteLine (isf.Scope); // User + ... }
© 2007, O'Reilly Media, Inc. All rights reserved