#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); } } }