#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace CSharpTest.Net.IO
{
///
/// Provides a class for managing a temporary file and making reasonable a attempt to remove it upon disposal.
///
[System.Diagnostics.DebuggerDisplay("{TempPath}")]
public class TempFile : IDisposable
{
private string _filename;
///
/// Attaches a new instances of a TempFile to the provided file path
///
public static TempFile Attach(string existingPath)
{
return new TempFile(existingPath);
}
///
/// Creates a temp file having the provided extension
///
[DebuggerNonUserCode]
public static TempFile FromExtension(string extensionWithDot)
{
return new TempFile(CreateTempPath(extensionWithDot));
}
///
/// Creates a temp file having the provided extension
///
[DebuggerNonUserCode]
public static string CreateTempPath(string extensionWithDot)
{
int attempt = 0;
while (true)
{
try
{
string path = Path.GetTempFileName();
if (string.IsNullOrEmpty(extensionWithDot))
{
if (!File.Exists(path))
File.Open(path, FileMode.CreateNew).Dispose();
return path;
}
if (File.Exists(path))
File.Delete(path);
path = Path.ChangeExtension(path, extensionWithDot);
File.Open(path, FileMode.CreateNew).Dispose();
return path;
}
catch (UnauthorizedAccessException)
{
if (++attempt < 10)
continue;
throw;
}
catch (IOException)
{
if (++attempt < 10)
continue;
throw;
}
}
}
///
/// Creates a temp file having a copy of the specified file
///
public static TempFile FromCopy(string srcFileName)
{
TempFile temp = FromExtension(Path.GetExtension(srcFileName));
try
{
File.Copy(srcFileName, temp.TempPath, true);
return temp;
}
catch
{
temp.Dispose();
throw;
}
}
///
/// Safely delete the provided file name
///
public static void Delete(string path)
{
bool exists = false;
try { exists = !String.IsNullOrEmpty(path) && File.Exists(path); }
catch (System.IO.IOException) { }
if(exists)
new TempFile(path).Dispose();
}
///
/// Constructs a new temp file with a newly created/empty file.
///
public TempFile() : this(Path.GetTempFileName()) { }
///
/// Manage the provided file path
///
public TempFile(string filename)
{
TempPath = filename;
}
///
/// Removes the file if Dispose() is not called
///
~TempFile() { try { Dispose(false); } catch { } }
///
/// Returns the temporary file path being managed.
///
public string TempPath
{
[DebuggerNonUserCode]
get
{
if (String.IsNullOrEmpty(_filename))
throw new ObjectDisposedException(GetType().ToString());
return _filename;
}
protected set
{
if (Exists)
TempFile.Delete(_filename);
if (!String.IsNullOrEmpty(_filename = value))
_filename = Path.GetFullPath(_filename);
}
}
/// Disposes of the temporary file
public void Dispose() { Dispose(true); }
///
/// Disposes of the temporary file
///
[DebuggerNonUserCode]
protected virtual void Dispose(bool disposing)
{
try
{
if (_filename != null && Exists)
File.Delete(_filename);
_filename = null;
if (disposing)
GC.SuppressFinalize(this);
}
catch (System.IO.IOException e)
{
string filename = _filename;
if (!disposing) //wait for next GC's collection
{
new TempFile(filename);
_filename = null;
}
Trace.TraceWarning("Unable to delete temp file: {0}, reason: {1}", filename, e.Message);
}
}
///
/// Detatches this instance from the temporary file and returns the temp file's path
///
public string Detatch()
{
GC.SuppressFinalize(this);
string name = _filename;
_filename = null;
return name;
}
///
/// Returns true if the current temp file exists.
///
[DebuggerNonUserCode]
public bool Exists { get { return !String.IsNullOrEmpty(_filename) && File.Exists(_filename); }}
///
/// Gets or sets the current length of the temp file. If setting the length on a file that
/// does not exist one will be created. If getting the length of a file that doesnt exist
/// zero will be returned.
///
public long Length
{
get { return !Exists ? 0L : Info.Length; }
set { using (Stream s = Open()) s.SetLength(value); }
}
///
/// Returns the FileInfo object for this temp file.
///
public FileInfo Info { get { return new FileInfo(TempPath); } }
/// Reads all bytes from the file
public byte[] ReadAllBytes() { return File.ReadAllBytes(TempPath); }
/// Writes all bytes to the file
public void WriteAllBytes(byte[] data) { File.WriteAllBytes(TempPath, data); }
/// Reads all UTF8 text from the file
public string ReadAllText() { return File.ReadAllText(TempPath, Encoding.UTF8); }
/// Writes all UTF8 text to the file
public void WriteAllText(string content) { File.WriteAllText(TempPath, content, Encoding.UTF8); }
///
/// Deletes the current temp file immediatly if it exists.
///
public void Delete() { if (Exists) File.Delete(TempPath); }
///
/// Re-Creates and Opens the temporary file for writing, multiple calls will truncate existing data.
///
public Stream Create() { return File.Open(TempPath, FileMode.Create, FileAccess.Write, FileShare.Read); }
///
/// Open or Create the temporary file for reading and writing
///
public Stream Open() { return File.Open(TempPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); }
///
/// Opens the temporary file for reading
///
public Stream Read() { return Read(FileShare.ReadWrite); }
///
/// Opens the temporary file for reading
///
public Stream Read(FileShare shared) { return File.Open(TempPath, FileMode.Open, FileAccess.Read, shared); }
///
/// Copies the file content to the specified target file name
///
public void CopyTo(string target) { CopyTo(target, false); }
///
/// Copies the file content to the specified target file name
///
public void CopyTo(string target, bool replace)
{
File.Copy(TempPath, target, replace);
}
}
}