using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
namespace Wayne.Lib.IO
{
///
/// Support class for files.
///
public class FileSupportNonStatic : IFileSupport
{
#region Properties
///
/// Default encoding for reading and writing text files.
///
public static readonly System.Text.Encoding DefaultEncoding = System.Text.Encoding.UTF8;
///
/// The Paths implementation to be used.
///
public IPaths Paths { get; private set; }
#endregion
///
/// Constructor. uses default paths implementation.
///
public FileSupportNonStatic()
{
Paths = new PathsImplementation(this.UnresolvedDirectoryPathExists(@"c:\"));
}
///
/// Constructor.
///
///
public FileSupportNonStatic(IPaths paths)
{
Paths = paths;
}
#region Open
///
/// Opens a file.
///
///
///
///
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public virtual Stream Open(string fileName, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, int retries, int delayBetweenRetries)
{
if (retries < 0)
throw new ArgumentException("Number of retries must be positive non-zero", "retries");
if (delayBetweenRetries < 0)
throw new ArgumentException("Delay between retries must be equal to or greater than zero.");
fileName = Paths.Parse(fileName);
int retriesLeft = retries;
do
{
try
{
return FileOpen(fileName, fileMode, fileAccess, fileShare);
}
catch (IOException)
{
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
catch (UnauthorizedAccessException)
{
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
}
while (true); //Exit either by returning, or by throwing the exception that occured.
}
///
/// Opens a file, using standard values for retries (100) and delayBetweenRetries(100)
///
///
///
///
///
///
public Stream Open(string fileName, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
{
return Open(fileName, fileMode, fileAccess, fileShare, 100, 100);
}
#endregion
#region Move
///
/// Moves a file.
///
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public void Move(string sourceFileName, string destinationFileName, int retries, int delayBetweenRetries)
{
if (retries <= 0)
throw new ArgumentException("Number of retries must be positive non-zero", "retries");
if (delayBetweenRetries < 0)
throw new ArgumentException("Delay between retries must be equal to or greater than zero.");
sourceFileName = Paths.Parse(sourceFileName);
destinationFileName = Paths.Parse(destinationFileName);
int retriesLeft = retries;
do
{
try
{
if (FileExists(destinationFileName))
FileDelete(destinationFileName);
FileMove(sourceFileName, destinationFileName);
return;
}
catch (IOException)
{
if (!FileExists(sourceFileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
catch (UnauthorizedAccessException)
{
if (!FileExists(sourceFileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
}
while (true); //Exit either by returning, or by throwing the exception that occured.
}
///
/// Moves a file, using standard values for retries (100) and delayBetweenRetries(100)
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public void Move(string sourceFileName, string destinationFileName)
{
Move(sourceFileName, destinationFileName, 100, 100);
}
///
/// Moves an entire directory from one location to another
///
///
///
public void MoveDirectory(string sourceDirName, string destDirName)
{
MoveDirectory(sourceDirName, destDirName, 100, 100);
}
///
/// Moves an entire directory from one location to another
///
///
///
///
///
public void MoveDirectory(string sourceDirName, string destDirName, int retries, int delayBetweenRetries)
{
if (retries <= 0)
throw new ArgumentException("Number of retries must be positive non-zero", "retries");
if (delayBetweenRetries < 0)
throw new ArgumentException("Delay between retries must be equal to or greater than zero.");
sourceDirName = Paths.Parse(sourceDirName);
destDirName = Paths.Parse(destDirName);
int retriesLeft = retries;
do
{
try
{
DirectoryMove(sourceDirName, destDirName);
return;
}
catch (IOException)
{
if (DirectoryExists(destDirName) || !DirectoryExists(sourceDirName)) //If the dest dir already exist -or- the source dir does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
catch (UnauthorizedAccessException)
{
if (DirectoryExists(destDirName) || !DirectoryExists(sourceDirName)) //If the dest dir already exist -or- the source dir does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
}
while (true); //Exit either by returning, or by throwing the exception that occured.
}
#endregion
#region Delete
///
/// Deletes a file
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public void Delete(string fileName, int retries, int delayBetweenRetries)
{
if (retries <= 0)
throw new ArgumentException("Number of retries must be positive non-zero", "retries");
if (delayBetweenRetries < 0)
throw new ArgumentException("Delay between retries must be equal to or greater than zero.");
fileName = Paths.Parse(fileName);
int retriesLeft = retries;
do
{
try
{
if (FileExists(fileName))
FileDelete(fileName);
return;
}
catch (IOException)
{
if (!FileExists(fileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
catch (UnauthorizedAccessException)
{
if (!FileExists(fileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
}
while (true); //Exit either by returning, or by throwing the exception that occured.
}
///
/// Deletes a file, using standard values for retries (100) and delayBetweenRetries(100)
///
///
[System.Diagnostics.DebuggerStepThrough]
public void Delete(string fileName)
{
Delete(fileName, 100, 100);
}
#endregion
#region SecureDelete
private ISecureDeleteSupport secureDeleteSupport;
private readonly object secureDeleteSupportSyncObj = new object();
///
/// Get- and set property for the SecureDelete support object. Needed to create backend to the secure delete function.
///
public ISecureDeleteSupport SecureDeleteSupport
{
get
{
lock (secureDeleteSupportSyncObj)
{
return secureDeleteSupport;
}
}
set
{
lock (secureDeleteSupportSyncObj)
{
secureDeleteSupport = value;
}
}
}
///
/// Deletes a file securely.
///
///
///
///
///
public void SecureDelete(string fileName, out bool sDeleteOK, int retries, int delayBetweenRetries)
{
lock (secureDeleteSupportSyncObj)
{
if (secureDeleteSupport == null)
throw new NullReferenceException("The SecureDeleteSupport property is not assigned!");
SecureDeleteSupport.SecureDelete(fileName, out sDeleteOK, retries, delayBetweenRetries);
}
}
///
/// Deletes a file securely.
///
///
///
public void SecureDelete(string fileName, out bool sDeleteOK)
{
SecureDelete(fileName, out sDeleteOK, 100, 100);
}
#endregion
#region Copy
///
/// Copy a file.
///
///
///
///
public void Copy(string sourceFileName, string destinationFileName, bool overwrite)
{
Copy(sourceFileName, destinationFileName, overwrite, 100, 100);
}
///
/// Copies a file.
///
///
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public virtual void Copy(string sourceFileName, string destinationFileName, bool overwrite, int retries, int delayBetweenRetries)
{
if (retries <= 0)
throw new ArgumentException("Number of retries must be positive non-zero", "retries");
if (delayBetweenRetries < 0)
throw new ArgumentException("Delay between retries must be equal to or greater than zero.");
sourceFileName = Paths.Parse(sourceFileName);
destinationFileName = Paths.Parse(destinationFileName);
int retriesLeft = retries;
do
{
try
{
if (FileExists(destinationFileName))
FileDelete(destinationFileName);
FileCopy(sourceFileName, destinationFileName, overwrite);
return;
}
catch (IOException)
{
if (!FileExists(sourceFileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
catch (UnauthorizedAccessException)
{
if (!FileExists(sourceFileName)) //If the source file does not even exist, then it is not worth looping.
throw;
retriesLeft--;
if (retriesLeft == 0)
throw;
ThreadSleep(delayBetweenRetries);
}
}
while (true); //Exit either by returning, or by throwing the exception that occured.
}
#endregion
#region LoadFromFile/SaveToFile
///
/// Read the lines of a text file into a string.
///
/// The path and file name.
public string LoadToString(string fileName)
{
return LoadToString(fileName, DefaultEncoding);
}
///
/// Read the lines of a text file into a string.
///
/// The path and file name.
/// The encoding.
public virtual string LoadToString(string fileName, System.Text.Encoding encoding)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (encoding == null)
throw new ArgumentNullException("encoding");
using (Stream stream = Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (StreamReader reader = new StreamReader(stream, encoding))
{
return reader.ReadToEnd();
}
}
}
///
/// Read the lines of a text file into an array of strings.
///
/// The path and file name.
public string[] LoadToStringArray(string fileName)
{
return LoadToStringArray(fileName, DefaultEncoding);
}
///
/// Read the lines of a text file into an array of strings.
///
/// The path and file name.
/// The encoding.
public string[] LoadToStringArray(string fileName, System.Text.Encoding encoding)
{
return Regex.Split(LoadToString(fileName, encoding), "\r\n");
}
///
/// Saves a text string to a file.
///
/// The path and file name.
/// The text to save.
public void SaveToFile(string fileName, string text)
{
SaveToFile(fileName, text, DefaultEncoding);
}
///
/// Saves a text string to a file.
///
/// The path and file name.
/// The lines to save.
public void SaveToFile(string fileName, string[] lines)
{
SaveToFile(fileName, lines, DefaultEncoding);
}
///
/// Saves a text string to a file.
///
/// The path and file name.
/// The text to save.
/// The encoding.
public void SaveToFile(string fileName, string text, System.Text.Encoding encoding)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (text == null)
throw new ArgumentNullException("text");
if (encoding == null)
throw new ArgumentNullException("encoding");
using (Stream stream = Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
byte[] bytes = encoding.GetBytes(text);
stream.Write(bytes, 0, bytes.Length);
}
}
///
/// Saves a text string to a file.
///
/// The path and file name.
/// The lines to save.
/// The encoding.
public void SaveToFile(string fileName, string[] lines, System.Text.Encoding encoding)
{
SaveToFile(fileName, string.Join("\r\n", lines), encoding);
}
///
/// Loads the specified XML file into the XmlDocument.
///
/// The XmlDocument to load.
/// The path and file name.
public void LoadXml(XmlDocument xmlDocument, string fileName)
{
LoadXml(xmlDocument, fileName, DefaultEncoding);
}
///
/// Loads the specified XML file into the XmlDocument.
///
/// The XmlDocument to load.
/// The path and file name.
/// The encoding.
public void LoadXml(XmlDocument xmlDocument, string fileName, System.Text.Encoding encoding)
{
xmlDocument.LoadXml(LoadToString(fileName, encoding));
}
#endregion
private IFileSupportExtension fileSupportExtension;
private readonly object fileSupportExtensionSyncObj = new object();
///
/// Gets or sets tha File support extension that can be different depending on the execution platform (WinCE or Win32)
///
public IFileSupportExtension FileSupportExtension
{
get
{
lock (fileSupportExtensionSyncObj)
{
return fileSupportExtension;
}
}
set
{
lock (fileSupportExtensionSyncObj)
{
fileSupportExtension = value;
}
}
}
///
/// Set creation time on a file.
///
///
public DateTime GetCreationTime(string fileName)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
return fileSupportExtension.GetCreationTime(fileName);
}
}
///
/// Set creation time on a file.
///
///
///
public void SetCreationTime(string fileName, DateTime dateTime)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
fileSupportExtension.SetCreationTime(fileName, dateTime);
}
}
///
/// Set last access time on a file.
///
///
public DateTime GetLastAccessTime(string fileName)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
return fileSupportExtension.GetLastAccessTime(fileName);
}
}
///
/// Set last access time on a file.
///
///
///
public void SetLastAccessTime(string fileName, DateTime dateTime)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
fileSupportExtension.SetLastAccessTime(fileName, dateTime);
}
}
///
/// Get last write time on the file.
///
///
public DateTime GetLastWriteTime(string fileName)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
return fileSupportExtension.GetLastWriteTime(fileName);
}
}
///
/// Set last write time on the file.
///
///
///
public void SetLastWriteTime(string fileName, DateTime dateTime)
{
lock (fileSupportExtensionSyncObj)
{
if (fileSupportExtension == null)
throw new NullReferenceException("The FileSupportExtension property is not assigned!");
fileSupportExtension.SetLastWriteTime(fileName, dateTime);
}
}
///
/// Checks if the file exists
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public virtual bool FileExists(string fileName)
{
return File.Exists(Paths.Parse(fileName));
}
///
/// Deletes the file.
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual void FileDelete(string fileName)
{
File.Delete(fileName);
}
///
/// Opens a file.
///
///
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual Stream FileOpen(string fileName, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
{
return File.Open(fileName, fileMode, fileAccess, fileShare);
}
///
/// Copies a file
///
///
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual void FileCopy(string sourceFileName, string destinationFileName, bool overwrite)
{
File.Copy(sourceFileName, destinationFileName, overwrite);
}
///
/// Moves a file
///
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual void FileMove(string sourceFileName, string destinationFileName)
{
File.Move(sourceFileName, destinationFileName);
}
///
/// Moves a directory
///
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual void DirectoryMove(string sourceDirName, string destinationDirName)
{
Directory.Move(sourceDirName, destinationDirName);
}
///
/// Puts the thread in sleep mode.
///
///
[System.Diagnostics.DebuggerStepThrough]
protected virtual void ThreadSleep(int millisecondsTimeout)
{
Thread.Sleep(millisecondsTimeout);
}
///
/// Copies the content of one directory into another.
///
///
///
///
public void CopyDirectory(string sourcePath, string destinationPath, bool recurse)
{
if (!DirectoryExists(sourcePath))
throw new DirectoryNotFoundException(string.Format("Directory {0} does not exist", sourcePath));
sourcePath = IO.Paths.Parse(sourcePath);
destinationPath = IO.Paths.Parse(destinationPath);
if (destinationPath[destinationPath.Length - 1] != Path.DirectorySeparatorChar)
destinationPath += Path.DirectorySeparatorChar;
if (sourcePath[sourcePath.Length - 1] != Path.DirectorySeparatorChar)
sourcePath += Path.DirectorySeparatorChar;
EnsureDirectoryExists(destinationPath);
//Copy all the folders.
string[] subDirectories = GetDirectories(sourcePath, true);
foreach (var subDir in subDirectories)
{
string destinationFolder = SourceToDest(sourcePath, destinationPath, subDir);
EnsureDirectoryExists(destinationFolder);
}
//Copy all the files.
string[] files = GetFiles(sourcePath, "*.*", true);
foreach (var file in files)
{
Copy(file, SourceToDest(sourcePath, destinationPath, file), true);
}
}
private string SourceToDest(string sourcePath, string destinationPath, string sourceSubDir)
{
string replace = sourceSubDir.Replace(sourcePath, "");
string result = Path.Combine(destinationPath, replace);
return result;
}
///
/// Returns the names of files in the specified directory that match the specified search pattern.
///
/// The directory to search.
/// The search string to match against the names of files in path. The parameter cannot end in two periods ("..") or contain two periods ("..") followed by System.IO.Path.DirectorySeparatorChar or System.IO.Path.AltDirectorySeparatorChar, nor can it contain any of the characters in System.IO.Path.InvalidPathChars.
///
public string[] GetFiles(string path, string searchPattern)
{
return GetFiles(path, searchPattern, false);
}
///
/// Returns the names of files in the specified directory that match the specified search pattern.
///
/// The directory to search.
/// The search string to match against the names of files in path. The parameter cannot end in two periods ("..") or contain two periods ("..") followed by System.IO.Path.DirectorySeparatorChar or System.IO.Path.AltDirectorySeparatorChar, nor can it contain any of the characters in System.IO.Path.InvalidPathChars.
/// Should the subdirectories be included in the search.
///
public virtual string[] GetFiles(string path, string searchPattern, bool recursive)
{
List files = new List();
files.AddRange(Directory.GetFiles(Paths.Parse(path), searchPattern));
if (recursive)
{
foreach (string directory in GetDirectories(path))
{
files.AddRange(GetFiles(directory, searchPattern, true));
}
}
return files.ToArray();
}
///
/// Returns the names of subdirectories in the specified directory that match the specified search pattern.
///
/// The directory to search.
///
public virtual string[] GetDirectories(string path)
{
return Directory.GetDirectories(Paths.Parse(path));
}
///
/// Returns the subdirectories of the path
///
///
/// True if the method should get all subdirectories recursively.
///
public string[] GetDirectories(string path, bool recursive)
{
if (!recursive) return GetDirectories(path);
var stack = new Stack();
stack.Push(path);
var dirsFound = new List();
while (stack.Any())
{
GetDirectories(stack.Pop()).ForEach(dir =>
{
stack.Push(dir);
dirsFound.Add(dir);
});
}
return dirsFound.ToArray();
}
///
/// Checks if directory exists
///
///
///
public virtual bool DirectoryExists(string path)
{
return Directory.Exists(Paths.Parse(path));
}
///
/// Checks if the unresolved directory exits.
///
///
///
private bool UnresolvedDirectoryPathExists(string path)
{
return Directory.Exists(path);
}
///
/// Ensures the directory exists by trying to create it if it does not exist already.
///
///
///
[System.Diagnostics.DebuggerStepThrough]
public virtual bool EnsureDirectoryExists(string path)
{
path = Paths.Parse(path);
try
{
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
catch { }
return Directory.Exists(path);
}
///
/// OBSOLETE - Use EnsureDirectoryExists() instead.
///
///
[System.Diagnostics.DebuggerStepThrough]
[Obsolete("Use EnsureDirectoryExists() instead.")]
public virtual void EnsureDirectoriesExists(string directoryName)
{
EnsureDirectoryExists(directoryName);
}
///
/// Removes a directory.
///
///
///
///
public virtual bool RemoveDirectory(string path, bool onlyIfEmpty)
{
if (!Directory.Exists(path))
return true;
if (!onlyIfEmpty)
Directory.Delete(path, true);
else if ((GetFiles(path, "*.*").Length == 0) && (GetDirectories(path).Length == 0))
Directory.Delete(path);
return !Directory.Exists(path);
}
///
/// Checks if the filename is valid.
///
///
/// True if the filename is valid otherwise false.
public virtual bool IsValidFileName(string fileName)
{
return fileName != null && Regex.IsMatch(Paths.Parse(fileName), string.Format(@"^([^{0}]+[/\\])*[/\\]?[^{1}]+?$",
Regex.Escape(new string(Path.GetInvalidPathChars())),
Regex.Escape(new string(Path.GetInvalidPathChars()) + @":*?\/")));
}
///
/// Checks if the filepath is valid
///
///
/// True if the filepath is valid otherwise false.
public virtual bool IsValidPathName(string pathName)
{
return pathName != null && Regex.IsMatch(Paths.Parse(pathName), string.Format(@"^[^{0}]*$",
Regex.Escape(new string(Path.GetInvalidPathChars()))));
}
}
}