OSDN Git Service

#36500 書き込み最小化のクラスを作り直した。従来はsongs.db等で正しく書き込みがなされない(文字列の前に文字数の情報が出力されていない)問題があったが...
[dtxmania/dtxmania.git] / DTXManiaプロジェクト / コード / 全体 / FileStreamSSD.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.IO;
7 using System.Diagnostics;
8
9 namespace DTXMania
10 {
11         /// <summary>
12         /// SSD向けFileStream (ファイルの上書き保存時に、同じファイル内容を保存する場合は、ファイルの更新を行わない)
13         /// </summary>
14         public class FileStreamSSD : MemoryStream, IDisposable
15         {
16                 private string _filename;
17                 private FileMode _mode;
18                 private FileAccess _access;
19                 private MemoryStream _ms_org = null;
20                 private FileStream _fs;
21                 private bool disposed = false;
22
23                 /// <summary>
24                 /// (baseではなく)このクラスのClose()が実行されたかどうか
25                 /// </summary>
26                 private bool bClosed = false;
27
28
29
30                 #region [ コンストラクタ ]
31                 public FileStreamSSD()
32                 {
33                         throw new ArgumentException( "FileStreamSSD: 引数のないコンストラクタは使用できません。" );
34                 }
35
36                 public FileStreamSSD( string path )
37                         : this(path, FileMode.Create, FileAccess.Write)
38                 {
39                 }
40                 public FileStreamSSD( string path, FileMode mode, FileAccess access )
41                         : base()
42                 {
43                         if (mode != FileMode.Create)
44                         {
45                                 throw new ArgumentException(mode.ToString() + "は、FileStreamSSD()でサポートしていません。");
46                         }
47                         if (access != FileAccess.Write)
48                         {
49                                 throw new ArgumentException(access.ToString() + "は、FileStreamSSD()でサポートしていません。");
50                         }
51                         _filename = path;
52                         _mode = mode;
53                         _access = access;
54                 }
55                 #endregion
56
57                 /// <summary>
58                 /// StreamのClose。元ファイルとのコンペアを行い、一致していればファイルの上書きをしない
59                 /// </summary>
60                 public new void Close()
61                 {
62                         bool bSame = true;
63                         Flush();
64
65                         // 元ファイルがなければ、無条件に上書きコースへ。
66                         if ( !File.Exists( _filename ) )
67                         {
68                                 bSame = false;
69                         }
70                         else
71                         // まず、既存ファイルをMemoryStreamにコピー
72                         {
73                                 using ( _fs = new FileStream( _filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete ) )
74                                 {
75                                         // 元ファイルとファイルサイズが異なる場合は、
76                                         if ( _fs.Length != this.Length )
77                                         {
78                                                 bSame = false;
79                                         }
80                                         else
81                                         {
82                                                 _ms_org = new MemoryStream();
83                                                 _fs.CopyTo( _ms_org );
84                                         }
85                                 };
86                                 _fs = null;
87                         }
88
89                         if ( bSame )    // まだ新旧ファイルが一致している可能性があれば...
90                         {
91                                 // MemoryStream同士のコンペア
92                                 _ms_org.Seek( 0, SeekOrigin.Begin );
93                                 this.Seek( 0, SeekOrigin.Begin );
94
95                                 try
96                                 {
97                                         while (this.Position < this.Length)
98                                         {
99                                                 int dorg = _ms_org.ReadByte();
100                                                 int dnew = this.ReadByte();
101                                                 if (dorg != dnew)
102                                                 {
103                                                         bSame = false;
104                                                         break;
105                                                 }
106                                         }
107                                 }
108                                 catch   // ファイルサイズが同じ場合のみtry内に来るため、通常ここには来ないはずだが、念のためbSame=false側に倒しておく
109                                 {
110                                         bSame = false;
111                                 }
112                         }
113                         if ( _ms_org != null )
114                         {
115                                 _ms_org.Close();
116                                 _ms_org.Dispose();
117                                 _ms_org = null;
118                         }
119                         this.Seek( 0, SeekOrigin.Begin );
120
121                         // 元ファイルと新規ファイルが一致していない場合、新規ファイルで上書きする
122                         if ( !bSame )
123                         {
124                                 Trace.TraceInformation( Path.GetFileName( _filename ) + ": 以前のファイルから変化があったため、書き込みを実行します。" );
125                                 using ( _fs = new FileStream( _filename, _mode, _access ) )
126                                 {
127                                         this.CopyTo( _fs );
128                                 }       // _fs will be closed and disposed, by using()
129                                 _fs = null;
130                         }
131                         else
132                         {
133                                 Trace.TraceInformation( Path.GetFileName( _filename ) + ": 以前のファイルから変化がなかったため、書き込みを行いません。" );
134                         }
135
136                         bClosed = true;         // base.Close()の前にフラグ変更のこと。さもないと、無限に再帰実行される
137                         Dispose();
138                 }
139
140
141
142                 #region [ Dispose-Finallizeパターン実装 ]
143                 //-----------------
144                 public new void Dispose()
145                 {
146                         this.Dispose( true );
147                         GC.SuppressFinalize( this );
148                         base.Dispose();
149                 }
150                 protected override void Dispose( bool disposing)
151                 {
152                         if (!this.disposed)
153                         {
154                                 try
155                                 {
156                                         if (this._ms_org != null)
157                                         {
158                                                 this._ms_org.Close();
159                                                 this._ms_org.Dispose();
160                                                 this._ms_org = null;
161                                         }
162                                         if (this._fs != null)
163                                         {
164                                                 this._fs.Close();
165                                                 this._fs.Dispose();
166                                                 this._fs = null;
167                                         }
168                                         if (!bClosed)
169                                         {
170                                                 this.Close();               // Close()なしでDispose()された場合用 (DataContractSerializer経由だと、ここに来る)
171                                         }
172                                         this.disposed = true;
173                                 }
174                                 finally
175                                 {
176                                         base.Dispose(disposing);
177                                 }
178                         }
179                 }
180                 ~FileStreamSSD()
181                 {
182                         this.Dispose( false );
183                 }
184                 #endregion
185         }
186 }