Now that you have seen how to use the various classes to manipulate files and directories, let's put them to good use by building a simple file explorer that displays all the subdirectories and files within a specified directory.
The following program contains the PrintFoldersinCurrentDirectory()
function, which recursively traverses a directory's subdirectories and prints out its contents:
class Program {
static string path = @"C:\Program Files\Microsoft Visual Studio 9.0\VC#";
static void Main(string[] args) {
DirectoryInfo di = new DirectoryInfo(path);
Console.WriteLine(di.FullName);
PrintFoldersinCurrentDirectory(di, -1);
Console.ReadLine();
}
private static void PrintFoldersinCurrentDirectory(
DirectoryInfo directory, int level) {
level++;
//---print all the subdirectories in the current directory---
foreach (DirectoryInfo subDir in directory.GetDirectories()) {
for (int i = 0; i <= level * 3; i++)
Console.Write(" ");
Console.Write("| ");
//---display subdirectory name---
Console.WriteLine(subDir.Name);
//---display all the files in the subdirectory---
FileInfo[] files = subDir.GetFiles();
foreach (FileInfo file in files) {
//---display the spaces---
for (int i = 0; i <= (level+1) * 3; i++) Console.Write(" ");
//---display filename---
Console.WriteLine("* " + file.Name);
}
//---explore its subdirectories recursively---
PrintFoldersinCurrentDirectory(subDir, level);
}
}
}
Figure 11-2 shows the output of the program.
Figure 11-2
A stream is an abstraction of a sequence of bytes. The bytes may come from a file, a TCP/IP socket, or memory. In .NET, a stream is represented, aptly, by the Stream
class. The
Stream class provides a generic view of a sequence of bytes.
The Stream
class forms the base class of all other streams, and it is also implemented by the following classes:
□ BufferedStream
— Provides a buffering layer on another stream to improve performance
□ FileStream
— Provides a way to read and write files
□ MemoryStream
— Provides a stream using memory as the backing store
□ NetworkStream
— Provides a way to access data on the network
□ CryptoStream
— Provides a way to supply data for cryptographic transformation
□ Streams fundamentally involve the following operations:
□ Reading
□ Writing
□ Seeking
The Stream
class is defined in the System.IO
namespace. Remember to import that namespace when using the class.
The following code copies the content of one binary file and writes it into another using the Stream
class:
try {
const int BUFFER_SIZE = 8192;
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
string filePath = @"C:\temp\VS2008Pro.png";
string filePath_backup = @"C:\temp\VS2008Pro_bak.png";
Stream s_in = File.OpenRead(filePath);
Stream s_out = File.OpenWrite(filePath_backup);
while ((bytesRead = s_in.Read(buffer, 0, BUFFER_SIZE)) > 0) {
s_out.Write(buffer, 0, bytesRead);
}
s_in.Close();
s_out.Close();
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
This first opens a file for reading using the static OpenRead()
method from the File class. In addition, it opens a file for writing using the static OpenWrite()
method. Both methods return a FileStream
object.
While the OpenRead()
and OpenWrite()
methods return a FileStream
object, you can actually assign the returning type to a Stream
object because the FileStream
object inherits from the Stream
object.
To copy the content of one file into another, you use the Read()
method from the Stream
class and read the content from the file into an byte array. Read()
returns the number of bytes read from the stream (in this case the file) and returns 0 if there are no more bytes to read. The Write()
method of the Stream
class writes the data stored in the byte array into the stream (which in this case is another file). Finally, you close both the Stream
objects.
In addition to the Read()
and Write()
methods, the Stream
object supports the following methods:
□ ReadByte()
— Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream
□ WriteByte()
— Writes a byte to the current position in the stream and advances the position within the stream by 1 byte
□ Seek()
— Sets the position within the current stream
The following example writes some text to a text file, closes the file, reopens the file, seeks to the fourth position in the file, and reads the next six bytes:
try {
const int BUFFER_SIZE = 8192;
string text = "The Stream class is defined in the System.IO namespace.";
byte[] data = ASCIIEncoding.ASCII.GetBytes(text);
byte[] buffer = new byte[BUFFER_SIZE];
string filePath = @"C:\temp\textfile.txt";
//---writes some text to file---
Stream s_out = File.OpenWrite(filePath);
s_out.Write(data, 0, data.Length);
s_out.Close();
//---opens the file for reading---
Stream s_in = File.OpenRead(filePath);
//---seek to the fourth position---
s_in.Seek(4, SeekOrigin.Begin);
//---read the next 6 bytes---
int bytesRead = s_in.Read(buffer, 0, 6);
Console.WriteLine(ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead));
s_in.Close();
s_out.Close();
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
To improve its performance, the BufferedStream
class works with another Stream
object. For instance, the previous example used a buffer size of 8192 bytes when reading from a text file. However, that size might not be the ideal size to yield the optimum performance from your computer. You can use the BufferedStream
class to let the operating system determine the optimum buffer size for you. While you can still specify the buffer size to fill up your buffer when reading data, your buffer will now be filled by the BufferedStream
class instead of directly from the stream (which in the example is from a file). The BufferedStream
class fills up its internal memory store in the size that it determines is the most efficient.
Читать дальше