File system manipulation
This article shows how to perform tasks involving reading and writing files from various partitions by using the C#.net programming API. In particular, it covers exploring the directory structure, finding out what files and folders are present, and performing other file-related operations, such as moving, copying, and deleting objects from the disk. The core motive behind this article is to explore types defined in the System.IO namespace and to promote an understanding of various ways to read from and write to character-based, binary-based, and string-based data stores.
Become a certified reverse engineer!
The anatomy of a file system
The System.IO provides four classes that allow you to manipulate individual files and interact with a machine directory structure. The Directory and File directly extends the System.Object to allow creating, copying, moving, and deleting using various static methods only, never instantiated. The FileInfo and DirectoryInfo types are derived from the abstract class FileSystemInfo type and they are typically, employed for obtaining full details of a file or directory because their members tend strongly to return type objects. They implement roughly the same public methods as Directory and File, but they are stateful and the members of these classes are not static.
In the .NET framework, the System.IO namespace is the region for the base class libraries devoted to file-based input and output services. Like any namespace, the System.IO namespace defines a set of classes, interface, enumeration, structure, and delegates. The following table outlines the core members of this namespace as following;
Reading disk partitions
The System.IO provides a class DriveInfo in order to manipulate system drive-related tasks. The DriveInfo class provides numerous details, such as displaying the total number of drives and calculating total hard disk space, available space, drive name, ready status, types, etc. Consider the following program, which showing the total disk drives
[c]
DriveInfo[] di = DriveInfo.GetDrives();
Console.WriteLine("Total Partitions");
foreach(DriveInfo items in di)
{
Console.WriteLine(items.Name);
}
[/c]
The following code snippets perform the rest of the DriveInfo class methods operation in detail. Full information about a particular drive is displayed like this:
[c]
using System;
using System.IO;
namespace DiskPartition
{
class Program
{
static void Main(string[] args)
{
DriveInfo[] di = DriveInfo.GetDrives();
Console.WriteLine("Total Partitions");
Console.WriteLine("---------------------");
foreach(DriveInfo items in di)
{
Console.WriteLine(items.Name);
}
Console.Write("nEnter the Partition::");
string ch = Console.ReadLine();
DriveInfo dInfo = new DriveInfo(ch);
Console.WriteLine("n");
Console.WriteLine("Drive Name::{0}",dInfo.Name);
Console.WriteLine("Total Space::{0}", dInfo.TotalSize);
Console.WriteLine("Free Space::{0}", dInfo.TotalFreeSpace);
Console.WriteLine("Drive Format::{0}", dInfo.DriveFormat);
Console.WriteLine("Volume Label::{0}", dInfo.VolumeLabel);
Console.WriteLine("Drive Type::{0}", dInfo.DriveType);
Console.WriteLine("Root dir::{0}", dInfo.RootDirectory);
Console.WriteLine("Ready::{0}", dInfo.IsReady);
Console.ReadKey();
}
}
}
[/c]
After compiling this program, it displays almost every detail of disk drives and a particular drive, as seen below:
Working with directory
The .NET framework stipulates two rudimentary classes, DirectoryInfo and Directory, in order to perform directory- related operations such creation, deletion.
DirectoryInfo Class
The DirectoryInfo class contains a set of members used for creation, deletion, moving, and enumeration over directories and subdirectories. The following code sample displays the information related to the temp directory in D drive:
[c]
DirectoryInfo di=new DirectoryInfo(@"D:temp");
Console.WriteLine("*******Directory Informations*******nn");
Console.WriteLine("Full Name={0}",di.FullName);
Console.WriteLine("Root={0}",di.Root);
Console.WriteLine("Attributes={0}", di.Attributes);
Console.WriteLine("Creation Time={0}", di.CreationTime);
Console.WriteLine("Name={0}", di.Name);
Console.WriteLine("Parent={0}", di.Parent);
[/c]
The output follows:
Typically, we make the assumption that the path passed in the constructor of DirectoryInfo class physically exists. However, if you attempt to interact with a nonexistent directory, then the CLR will throw an exception. So we need to create a directory first in order to handle exceptions:
[c]
DirectoryInfo di=new DirectoryInfo(@"D:tempxyz");
di.Create();
[/c]
We can also programmatically extend a directory structure using the CreateSubdirectory() method. The following code sample firs, creates a subdirectory in D drive, then in D:ajay:
[c]
DirectoryInfo di=new DirectoryInfo(@"D:");
di.CreateSubdirectory("ajay");
di.CreateSubdirectory(@"ajayajay11");
[/c]
Directory Class
The Directory class provides almost the same functionality as DirectoryInfo. The Directory typically returns string data rather than strongly typed DirectoryInfo objects. The following sample deletes the directory and subdirectory in D drive:
[c]
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo(@"d:abc");
Console.WriteLine("Name:{0}",di.FullName);
Console.Write("Are you sure to Delete:");
string str=Console.ReadLine();
if (str == "y")
{
Directory.Delete(@"d:abc", true);
}
Console.Write("Deleted.....");
}
[/c]
Reading and writing to files
Reading and writing operations are done through File objects. The following code snippet reads a text file that is located on machine somewhere:
[c]
private void button1_Click(object sender, EventArgs e)
{
try
{
textBox2.Text = File.ReadAllText(txtPath.Text);
}
catch (FileNotFoundException)
{
MessageBox.Show("File not Found....");
}
}
[/c]
First the user interface asks the user to enter the path of the file that he wants to display. Then that path is passed to the File method ReadAllText() method, which reads all the text integrated in the file and displays it in the text box.
Besides reading a file, we can write some contents over an existing text file by using the File class WriteAllTest() method, as follows:
[c]
File.WriteAllText(@"d:test.txt", textBox2.Text);
[/c]
It takes a path to save the file and a content input method medium, such as a text box or any other control. The following image depicts a text file reading by entering its corresponding path:
Stream
The .NET provides many objects such as FileStream, StreamReader/Writer, and BinaryReader/Writer to read and write data to a file. A stream basically represents a chunk of data flowing between a source and a destination. It provides a common way to interact with a sequence of bytes regardless of what kinds of devices store or display the bytes. The following table shows common stream member functions:
FileStream
A FileStream instance is used to read or write data to or from a file. In order to construct a FileStream, first we need a file that we want to access; second, the mode that indicates how we want to open the file; third, the access that indicates how we want to access a file; and finally, the share access, which specifies whether you want exclusive access to the file.
The FileStream can read or write only a single byte or an array of bytes. You will be required to encode the System.String type into a corresponding byte array. The System.Text namespace defines a type named encoding that provides members that encode and decode strings to an array of bytes. Once encoded, the byte array persists with the FileStream.Write() method. To read the bytes back into memory, you must reset the internal position of the stream and call the ReadByte() method. Finally, you display the raw byte array and the decoded string to the console:
[c]
using(FileStream fs=new FileStream(@"d:ajay123.doc",FileMode.Create))
{
string msg = "first program";
byte[] byteArray = Encoding.Default.GetBytes(msg);
fs.Write(byteArray, 0, byteArray.Length);
fs.Position = 0;
byte[] rFile = new byte[byteArray.Length];
for (int i = 0; i < byteArray.Length; i++)
{
rFile[i] = (byte)fs.ReadByte();
Console.WriteLine(rFile[i]);
}
Console.WriteLine(Encoding.Default.GetString(rFile));
}
[/c]
BinaryReader and BinaryWriter
The BinaryReader and BinaryWriter classes allow you to read and write discrete data types to an underlying stream in a compact binary format. The BinaryWriter class defines a highly overloaded Write() method to place a data type in the underlying stream.
The following sample first writes data contents to a new champu.dat file by using BinaryWriter. Later, to read the, BinaryReader class employs a number of methods, as follows:
[c]
class Program
{
static void Main(string[] args)
{
// writing
FileInfo fi = new FileInfo("champu.dat");
using (BinaryWriter bw = new BinaryWriter(fi.OpenWrite()))
{
int x = 007;
string str = "hello champu ,one day you will become doomkatu";
bw.Write(x);
bw.Write(str);
}
//Reading
FileInfo f = new FileInfo("champu.dat");
using (BinaryReader br = new BinaryReader(fi.OpenRead()))
{
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadString());
}
Console.ReadLine();
}
}
[/c]
StringReader and StringWriter
We can use StringWriter and StringReader to treat textual information as a stream of in-memory characters. This can prove helpful when you wish to append character-based information to an underlying buffer. The following code sample illustrates this by writing a block of string data to a StringWriter object, rather than to a file on the local hard drive:
[c]
static void Main(string[] args)
{
// writing
using (StringWriter sw = new StringWriter())
{
sw.WriteLine("helloooooooooooooooooooo");
// Reading
using (StringReader sr = new StringReader(sw.ToString()))
{
string input = null;
while((input = sr.ReadLine())!=null)
{
Console.WriteLine(input);
}
}
}
}
[/c]
Become a certified reverse engineer!
Summary
This article began by introducing the .NET file system and its detailed class hierarchy. We have learned to manipulate a physical file or directory on the hard drive by using File and Directory class. Next, we examined the Stream class in detail. The System.IO namespace provides numerous writer and reader types, for instance FileStream, BinaryStream, StringStream, etc. So this article gives you a full understanding of how to access data from the hard drive and write it back.