source: trunk/ab5.0/ablib/src/Classes/System/IO/FileStream.ab

Last change on this file was 605, checked in by イグトランス (egtra), 16 years ago

非同期入出力(Begin/End-Read/Writeメソッド)を実装。

File size: 11.8 KB
Line 
1'Classes/System/IO/FileStream.ab
2
3Namespace System
4Namespace IO
5
6/*
7(handle As IntPtr, access As FileAccess)
8(handle As IntPtr, access As FileAccess, ownsHandle As Boolean)
9(handle As IntPtr, access As FileAccess, ownsHandle As Boolean)
10(handle As IntPtr, access As FileAccess, ownsHandle As Boolean, isAsync As Boolean)
11(path As String, mode As FileMode)
12(path As String, mode As FileMode, access As FileAccess)
13(path As String, mode As FileMode, access As FileAccess, share As FileShare, useAsync As Boolean)
14(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
15(path As String, mode As FileMode, rights As FileSystemRights, share As FileShare, options As FileOptions)
16*/
17
18Class FileStream
19 Inherits Stream
20Protected
21 Sub initialize(ac As DWord, owns As Boolean, isAsync As Boolean)
22 Imports ActiveBasic
23 ownsHandle = owns
24 If (ac And GENERIC_READ) = 0 Then
25 readFn = New Detail.Unreadable
26 End If
27 If (ac And GENERIC_WRITE) = 0 Then
28 writeFn = New Detail.Unwritable
29 End If
30 If GetFileType(handle) <> FILE_TYPE_DISK Then
31 seekFn = New Detail.Unseekable
32 End If
33 If isAsync Then
34 If IsNothing(seekFn) Then
35 seekFn = New Detail.OverlappedSeekable
36 End If
37 If IsNothing(readFn) Then
38 readFn = New Detail.OverlappedReadable
39 End If
40 If IsNothing(writeFn) Then
41 writeFn = New Detail.OverlappedWritable
42 End If
43 Else
44 If IsNothing(seekFn) Then
45 seekFn = New Detail.Seekable
46 End If
47 If IsNothing(readFn) Then
48 readFn = New Detail.Readable
49 End If
50 If IsNothing(writeFn) Then
51 writeFn = New Detail.Writable
52 End If
53 End If
54 End Sub
55
56 Sub openFile(path As String, mode As FileMode, rights As DWord, share As FileShare, ByRef options As FileOptions)
57 Imports ActiveBasic
58 If IsNothing(path) Then
59 Throw New ArgumentNullException("path")
60 ElseIf path.Length = 0 Then
61 Throw New ArgumentException("path.Length = 0")
62 End If
63 Dim sh = share As DWord
64 Dim mo = mode As DWord
65 Dim op = options As DWord
66
67 If mode = FileMode.Append Then
68 mo = OPEN_ALWAYS
69 seekFn = New Detail.Unseekable
70 End If
71
72 Dim os = Environment.OSVersion
73 Dim platform = os.Platform As DWord
74 If platform = PlatformID.Win32Windows As DWord Or platform = PlatformID.Win32S As DWord Then
75 options = (op As DWord And Not FILE_FLAG_OVERLAPPED) As FileOptions
76 End If
77
78 handle = CreateFile(ToTCStr(path), rights, sh, ByVal NULL, mo, op, 0)
79 If handle = INVALID_HANDLE_VALUE Then
80 'エラー処理
81 'Throw ArgumentException
82 'Throw IOException
83 'Throw System.IO.FileNotFoundException
84 handle = 0
85 Detail.ThrowWinLastErrorIOException("Failed to open/create file.")
86 End If
87
88 filePath = path
89
90 If mode = FileMode.Append Then
91 Seek(0, SeekOrigin.End)
92 End If
93 End Sub
94
95 Sub initWithOpen(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
96 openFile(path, mode, access As DWord, share, options)
97 initialize(access, True, UseOverlappled(options))
98 End Sub
99
100 Sub initWithOpen2(path As String, mode As FileMode, rights As DWord, share As FileShare, options As FileOptions)
101 openFile(path, mode, rights, share, options)
102 Dim ac = 0 As DWord
103 If (rights And GENERIC_READ) Or (rights And FILE_READ_DATA) Then
104 ac = (ac As DWord Or GENERIC_READ) As FileAccess
105 End If
106 If (rights And GENERIC_WRITE) Or (rights And FILE_WRITE_DATA) Then
107 ac = (ac As DWord Or GENERIC_WRITE) As FileAccess
108 End If
109 initialize(ac, True, UseOverlappled(options))
110 End Sub
111
112 Static Function UseOverlappled(options As FileOptions) As Boolean
113 Dim op = options As DWord
114 If op And FILE_FLAG_OVERLAPPED Then
115 UseOverlappled = True
116 Else
117 UseOverlappled = False
118 End If
119 End Function
120
121 Sub FileStream()
122 End Sub
123Public
124 /*!
125 @brief ファイルを開く。
126 @param[in] path ファイルパス
127 @param[in] mode 開き方
128 @param[in] rights 使用するアクセス権の指定
129 @param[in] share 共有方法
130 @param[in] option オプション
131 @date 2008/08/21
132 @auther Egtra
133 */
134 Sub FileStream(path As String, mode As FileMode, rights As Security.AccessControl.FileSystemRights, share As FileShare, options As FileOptions)
135 initWithOpen2(path, mode, rights As DWord, share, options)
136 End Sub
137 /*!
138 @brief ファイルを開く。
139 @param[in] path ファイルパス
140 @param[in] mode 開き方
141 @param[in] access ファイルアクセスの指定
142 @param[in] share 共有方法
143 @param[in] option オプション
144 */
145 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
146 initWithOpen(path, mode, access, share, options)
147 End Sub
148 /*!
149 @brief ファイルを開く。
150 @param[in] path ファイルパス
151 @param[in] mode 開き方
152 @param[in] access ファイルアクセスの指定
153 @param[in] share 共有方法
154 @param[in] useAsync 非同期にするならTrue
155 @date 2008/08/21
156 @auther Egtra
157 */
158 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare, useAsync As Boolean)
159 Dim options = FileOptions.None
160 If useAsync Then
161 options = FileOptions.Asynchronous
162 End If
163 initWithOpen(path, mode, access, share, options)
164 End Sub
165 /*!
166 @brief ファイルを開く。
167 @param[in] path ファイルパス
168 @param[in] mode 開き方
169 @param[in] access ファイルアクセスの指定
170 @param[in] share 共有方法
171 */
172 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare)
173 initWithOpen(path,mode,access,share,FileOptions.None)
174 End Sub
175 /*!
176 @brief ファイルを開く。
177 @param[in] path ファイルパス
178 @param[in] mode 開き方
179 @param[in] access ファイルアクセスの指定
180 */
181 Sub FileStream(path As String, mode As FileMode, access As FileAccess)
182 initWithOpen(path,mode,access,FileShare.None,FileOptions.None)
183 End Sub
184 /*!
185 @brief ファイルを開く。
186 @param[in] path ファイルパス
187 @param[in] mode 開き方
188 */
189 Sub FileStream(path As String, mode As FileMode)
190 Dim access As FileAccess
191 Select Case mode
192 Case FileMode.Append
193 access=FileAccess.Write
194 Case FileMode.Create
195 access=FileAccess.ReadWrite
196 Case FileMode.CreateNew
197 access=FileAccess.ReadWrite
198 Case FileMode.Open
199 access=FileAccess.ReadWrite
200 Case FileMode.OpenOrCreate
201 access=FileAccess.ReadWrite
202 Case FileMode.Truncate
203 access=FileAccess.Write
204 End Select
205 initWithOpen(path,mode,access,FileShare.None,FileOptions.None)
206 End Sub
207 /*!
208 @brief 既存ハンドルを基にストリームを作る。
209 @param[in] h ハンドル
210 @param[in] access ファイルアクセスの指定
211 @param[in] owns 所有権を保持するかどうか(TrueならDispose時に基のハンドルも閉じる)
212 @param[in] isAsync 重複IOを使用するかどうか
213 @date 2008/02/26
214 @auther Egtra
215 @todo SafeFileHandle版に置き換えること
216 */
217 Sub FileStream(h As HANDLE, access As FileAccess, owns = True As Boolean, isAsync = False As Boolean)
218 handle = h
219 initialize(access, owns, isAsync)
220 End Sub
221Public
222 /*!
223 @brief ファイルが読み込みに対応しているかを返す
224 */
225 Override Function CanRead() As Boolean
226 Return readFn.CanRead
227 End Function
228
229 /*!
230 @brief ファイルがシークに対応しているかを返す
231 */
232 Override Function CanSeek() As Boolean
233 Return seekFn.CanSeek
234 End Function
235
236 /*!
237 @brief ファイルが書き込みに対応しているかを返す
238 */
239 Override Function CanWrite() As Boolean
240 Return writeFn.CanWrite
241 End Function
242
243 /*!
244 @brief 保持しているハンドルを返す
245 */
246 Function Handle() As HANDLE
247 Return handle
248 End Function
249
250 Override Function Length() As QWord
251 disposedCheck()
252 Length = seekFn.Length(This)
253 End Function
254
255 Function Name() As String
256 Return This.filePath
257 End Function
258
259 Override Sub Position(value As QWord)
260 disposedCheck()
261 seekFn.Position(This, value)
262 End Sub
263 Override Function Position() As QWord
264 disposedCheck()
265 Position = seekFn.Position(This)
266 End Function
267
268Public
269 /* Safe~Handle系の実装は要相談!! */
270/* Function SafeFileHandle() As SafeFileHandle
271 End Function*/
272
273Public
274 Override Function BeginRead(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
275 disposedCheck()
276 If buffer = 0 Then
277 Throw New ArgumentNullException("FileStream.BeginRead", "buffer")
278 End If
279 BeginRead = readFn.BeginRead(This, buffer, offset, count, callback, state)
280 End Function
281
282 Override Function BeginWrite(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
283 disposedCheck()
284 If buffer = 0 Then
285 Throw New ArgumentNullException("FileStream.BeginWrite", "buffer")
286 End If
287 BeginWrite = writeFn.BeginWrite(This, buffer, offset, count, callback, state)
288 End Function
289
290 Override Function EndRead(asyncResult As System.IAsyncResult) As Long
291 disposedCheck()
292 EndRead = readFn.EndRead(This, asyncResult)
293 End Function
294
295 Override Sub EndWrite(asyncResult As System.IAsyncResult)
296 disposedCheck()
297 writeFn.EndWrite(This, asyncResult)
298 End Sub
299
300 Override Sub Flush()
301 disposedCheck()
302 Dim ret = FlushFileBuffers(This.handle)
303 If ret = FALSE Then
304 Detail.ThrowWinLastErrorIOException("FileStream.Flush: Failed to flush.")
305 End If
306 End Sub
307
308/* Function GetAccessControl() As FileSecurity
309 FileSecurityの実装がまだできてない。
310 End Function*/
311
312 Sub Lock(position As QWord, length As QWord)
313 disposedCheck()
314 If position < 0 Then
315 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.UInt64(position), "position")
316 ElseIf length < 0 Then
317 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.UInt64(length), "length")
318 End If
319 If LockFile(handle, LODWORD(position), HIDWORD(position), LODWORD(length), HIDWORD(length)) = FALSE Then
320 Detail.ThrowWinLastErrorIOException("FileStream.Lock: Failed to lock.")
321 End If
322 End Sub
323
324 Override Function Read(buffer As *Byte, offset As Long, count As Long) As Long
325 disposedCheck()
326 If buffer = 0 Then
327 Throw New ArgumentNullException("FileStream.Read", "buffer")
328 End If
329 Read = readFn.Read(This, buffer, offset, count)
330 End Function
331
332 /*!
333 @brief ストリームの現在位置を移動させる。
334 @param[in] offset originからの移動量
335 @param[in] origin 移動の基準位置
336 @return 移動後の新しい現在位置
337 @exception DisposedException 既にストリームが閉じられている場合
338 @exception ArgumentException 移動後の位置が負の位置(ファイル先頭より手前)になる場合
339 @exception IOException その他エラーが発生した場合
340 */
341 Override Function Seek(offset As Int64, origin As SeekOrigin) As Int64
342 disposedCheck()
343 Seek = seekFn.Seek(This, offset, origin)
344 End Function
345
346/* Sub SetAccessControl(fileSecurity As FileSecurity)
347 FileSecurityの実装がまだできてない。
348 End Sub*/
349
350 Override Sub SetLength(value As QWord)
351 disposedCheck()
352 seekFn.SetLength(This, value)
353 End Sub
354
355 Override Function ToString() As String
356 Return This.Name()
357 End Function
358
359 Sub Unlock(position As QWord, length As QWord)
360 disposedCheck()
361 Dim ret = UnlockFile(handle, LODWORD(position), HIDWORD(position), LODWORD(length), HIDWORD(length))
362 If ret = FALSE Then
363 Detail.ThrowWinLastErrorIOException("FileStream.Unlock failed")
364 End If
365 End Sub
366
367 Override Sub Write(buffer As *Byte, offset As Long, count As Long)
368 disposedCheck()
369 If buffer = 0 Then
370 Throw New ArgumentNullException("FileStream.Write", "buffer")
371 End If
372 writeFn.Write(This, buffer, offset, count)
373 End Sub
374
375Protected
376 Override Sub Dispose(disposing As Boolean)
377 If handle <> 0 Then
378 CloseHandle(InterlockedExchangePointer(ByVal VarPtr(handle), NULL))
379 End If
380 End Sub
381
382 Sub disposedCheck()
383 If handle = 0 Then
384 Throw New ObjectDisposedException("FileStream: This stream has already closed.")
385 End If
386 End Sub
387
388Private
389 handle As HANDLE
390 seekFn As Detail.SeekFunctions
391 readFn As Detail.ReadFunctions
392 writeFn As Detail.WriteFunctions
393 filePath As String
394 ownsHandle As Boolean
395End Class
396
397End Namespace
398End Namespace
Note: See TracBrowser for help on using the repository browser.