OSDN Git Service

DTXManiaソリューション、DTXManiaプロジェクト、DTXCreatorプロジェクト、FDKプロジェクトについて英語化。
[dtxmania/dtxmania.git] / DTXMania / コード / 全体 / FileStreamSSD.cs
diff --git a/DTXMania/コード/全体/FileStreamSSD.cs b/DTXMania/コード/全体/FileStreamSSD.cs
new file mode 100644 (file)
index 0000000..189d849
--- /dev/null
@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using System.Diagnostics;
+
+namespace DTXMania
+{
+       /// <summary>
+       /// SSD向けFileStream (ファイルの上書き保存時に、同じファイル内容を保存する場合は、ファイルの更新を行わない)
+       /// </summary>
+       public class FileStreamSSD : MemoryStream, IDisposable
+       {
+               private string _filename;
+               private FileMode _mode;
+               private FileAccess _access;
+               private MemoryStream _ms_org = null;
+               private FileStream _fs;
+               private bool disposed = false;
+
+               /// <summary>
+               /// (baseではなく)このクラスのClose()が実行されたかどうか
+               /// </summary>
+               private bool bClosed = false;
+
+
+
+               #region [ コンストラクタ ]
+               public FileStreamSSD()
+               {
+                       throw new ArgumentException( "FileStreamSSD: 引数のないコンストラクタは使用できません。" );
+               }
+
+               public FileStreamSSD( string path )
+                       : this(path, FileMode.Create, FileAccess.Write)
+               {
+               }
+               public FileStreamSSD( string path, FileMode mode, FileAccess access )
+                       : base()
+               {
+                       if (mode != FileMode.Create)
+                       {
+                               throw new ArgumentException(mode.ToString() + "は、FileStreamSSD()でサポートしていません。");
+                       }
+                       if (access != FileAccess.Write)
+                       {
+                               throw new ArgumentException(access.ToString() + "は、FileStreamSSD()でサポートしていません。");
+                       }
+                       _filename = path;
+                       _mode = mode;
+                       _access = access;
+               }
+               #endregion
+
+               /// <summary>
+               /// StreamのClose。元ファイルとのコンペアを行い、一致していればファイルの上書きをしない
+               /// </summary>
+               public new void Close()
+               {
+                       bool bSame = true;
+                       Flush();
+
+                       // 元ファイルがなければ、無条件に上書きコースへ。
+                       if ( !File.Exists( _filename ) )
+                       {
+                               bSame = false;
+                       }
+                       else
+                       // まず、既存ファイルをMemoryStreamにコピー
+                       {
+                               using ( _fs = new FileStream( _filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete ) )
+                               {
+                                       // 元ファイルとファイルサイズが異なる場合は、
+                                       if ( _fs.Length != this.Length )
+                                       {
+                                               bSame = false;
+                                       }
+                                       else
+                                       {
+                                               _ms_org = new MemoryStream();
+                                               _fs.CopyTo( _ms_org );
+                                       }
+                               };
+                               _fs = null;
+                       }
+
+                       if ( bSame )    // まだ新旧ファイルが一致している可能性があれば...
+                       {
+                               // MemoryStream同士のコンペア
+                               _ms_org.Seek( 0, SeekOrigin.Begin );
+                               this.Seek( 0, SeekOrigin.Begin );
+
+                               try
+                               {
+                                       while (this.Position < this.Length)
+                                       {
+                                               int dorg = _ms_org.ReadByte();
+                                               int dnew = this.ReadByte();
+                                               if (dorg != dnew)
+                                               {
+                                                       bSame = false;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               catch   // ファイルサイズが同じ場合のみtry内に来るため、通常ここには来ないはずだが、念のためbSame=false側に倒しておく
+                               {
+                                       bSame = false;
+                               }
+                       }
+                       if ( _ms_org != null )
+                       {
+                               _ms_org.Close();
+                               _ms_org.Dispose();
+                               _ms_org = null;
+                       }
+                       this.Seek( 0, SeekOrigin.Begin );
+
+                       // 元ファイルと新規ファイルが一致していない場合、新規ファイルで上書きする
+                       if ( !bSame )
+                       {
+                               Trace.TraceInformation( Path.GetFileName( _filename ) + ": 以前のファイルから変化があったため、書き込みを実行します。" );
+                               using ( _fs = new FileStream( _filename, _mode, _access ) )
+                               {
+                                       this.CopyTo( _fs );
+                               }       // _fs will be closed and disposed, by using()
+                               _fs = null;
+                       }
+                       else
+                       {
+                               Trace.TraceInformation( Path.GetFileName( _filename ) + ": 以前のファイルから変化がなかったため、書き込みを行いません。" );
+                       }
+
+                       bClosed = true;         // base.Close()の前にフラグ変更のこと。さもないと、無限に再帰実行される
+                       Dispose();
+               }
+
+
+
+               #region [ Dispose-Finallizeパターン実装 ]
+               //-----------------
+               public new void Dispose()
+               {
+                       this.Dispose( true );
+                       GC.SuppressFinalize( this );
+                       base.Dispose();
+               }
+               protected override void Dispose( bool disposing)
+               {
+                       if (!this.disposed)
+                       {
+                               try
+                               {
+                                       if (this._ms_org != null)
+                                       {
+                                               this._ms_org.Close();
+                                               this._ms_org.Dispose();
+                                               this._ms_org = null;
+                                       }
+                                       if (this._fs != null)
+                                       {
+                                               this._fs.Close();
+                                               this._fs.Dispose();
+                                               this._fs = null;
+                                       }
+                                       if (!bClosed)
+                                       {
+                                               this.Close();               // Close()なしでDispose()された場合用 (DataContractSerializer経由だと、ここに来る)
+                                       }
+                                       this.disposed = true;
+                               }
+                               finally
+                               {
+                                       base.Dispose(disposing);
+                               }
+                       }
+               }
+               ~FileStreamSSD()
+               {
+                       this.Dispose( false );
+               }
+               #endregion
+       }
+}