Guard Clauses
You have code like:
public virtual string ReadFileContents(string filePath, Encoding fileEncoding) { string returnValue = string.Empty; if (this.FileExists(filePath)) { ... do stuff returnValue = ..... } return returnValue; }
This would be better written as a guard clause:
public virtual string ReadFileContents(string filePath, Encoding fileEncoding) {
if (!this.FileExists(filePath)) {
return string.Empty;
}
... do stuff
return ....;
}
##Performance
Your concepts of 'large' and 'very large', are unconventional. I would consider 'large' to be in the > 100MiB ballpark, and very large to be > 4GiB (more than 32-bit size).
This has impacted the features you consider to be performance-enhancing. All file-systems I know of use at least a 512-byte extent, with the extends merged in to at least 4KiB blocks. If you are buffering data, I would recommend at least a 4KiB buffer. I have done similar things in the past, and I now typically use a 1MiB buffer to get queued reads happening.
I would thus have a buffer like:
var bufferSize = Math.Min(1024 * 1024, fs.Length)
byte[] bufferBlock = new byte[bufferSize];
That will set a buffer that can read all, or big chunks of the file.
If you do it that way, you can also remove the code path for files that are smaller than the buffer, they become irrelevant.
##Byte[] method: byte[] ReadFileContents(string filePath)
This method is horrible overkill. Since you have to return all the bytes anyway, you may as well just allocate a single large buffer for the file size, populate it, and return it.
if (fs.Length > (long)Int32.MaxValue)
{
... throw appropriate exception
}
byte[] returnValue = new byte[fsbyte[(int32)fs.Length];