source: trunk/ab5.0/ablib/src/Classes/System/IO/FileStreamImpl.ab@ 668

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

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

File size: 18.9 KB
Line 
1'Classes/System/IO/FileStreamImpl.ab
2
3Namespace System
4Namespace IO
5Namespace Detail
6
7Sub ThrowIfFilePointerFunctionFailed(dwLow As DWord)
8 If dwLow = INVALID_FILE_SIZE Then
9 Dim error = GetLastError()
10 If error <> NO_ERROR Then
11 Detail.ThrowWinIOException("FileStream: Failed to position or file size function.", error)
12 End If
13 End If
14End Sub
15
16/*!
17@brief シーク系関数の集合
18@date 2008/08/21
19@auther Egtra
20*/
21Class SeekFunctions
22Public
23 Abstract Function CanSeek() As Boolean
24 Abstract Function Seek(s As FileStream, offset As Int64, origin As SeekOrigin) As Int64
25 Abstract Sub Position(s As FileStream, value As QWord)
26 Abstract Function Position(s As FileStream) As QWord
27 Abstract Function Length(s As FileStream) As QWord
28 Abstract Sub SetLength(s As FileStream, value As QWord)
29End Class
30
31/*!
32@brief シークできない実装
33@date 2008/08/21
34@auther Egtra
35*/
36Class Unseekable
37 Inherits SeekFunctions
38Public
39 Override Function CanSeek() As Boolean
40 Return False
41 End Function
42 Override Function Seek(s As FileStream, offset As Int64, origin As SeekOrigin) As Int64
43 Throw New NotSupportedException("FileStream.Seek")
44 End Function
45 Override Sub Position(s As FileStream, vvalue As QWord)
46 Throw New NotSupportedException("FileStream.Position")
47 End Sub
48 Override Function Position(s As FileStream) As QWord
49 Throw New NotSupportedException("FileStream.Position")
50 End Function
51 Override Function Length(s As FileStream) As QWord
52 Throw New NotSupportedException("FileStream.Length")
53 End Function
54 Override Sub SetLength(s As FileStream, value As QWord)
55 Throw New NotSupportedException("FileStream.SetLength")
56 End Sub
57End Class
58
59/*!
60@brief シークできる実装
61@date 2008/08/21
62@auther Egtra
63*/
64Class Seekable
65 Inherits SeekFunctions
66Public
67 Override Function CanSeek() As Boolean
68 Return True
69 End Function
70 Override Function Seek(s As FileStream, offset As Int64, origin As SeekOrigin) As Int64
71 Dim seek = VarPtr(offset) As *LARGE_INTEGER
72 Dim ret = SetFilePointer(s.Handle, seek->LowPart As Long, VarPtr(seek->HighPart), origin As DWord)
73 If ret = INVALID_SET_FILE_POINTER Then
74 Dim error = GetLastError()
75 If error = ERROR_NEGATIVE_SEEK Then
76 Throw New ArgumentException("FileStream.Seek: Cannot seek to negative offset.")
77 ElseIf error <> NO_ERROR Then
78 Detail.ThrowWinIOException("FileStream.Seek: Failed to seek.", error)
79 End If
80 End If
81 seek->LowPart = ret
82 Seek = offset
83 End Function
84 Override Sub Position(s As FileStream, value As QWord)
85 Dim position = VarPtr(value) As *LARGE_INTEGER
86 With position[0]
87 Dim ret = SetFilePointer(s.Handle, .LowPart As Long, VarPtr(.HighPart), FILE_BEGIN)
88 ThrowIfFilePointerFunctionFailed(ret)
89 End With
90 End Sub
91 Override Function Position(s As FileStream) As QWord
92 Dim position = VarPtr(Position) As *LARGE_INTEGER
93 With position[0]
94 .LowPart = SetFilePointer(s.Handle, .LowPart As Long, VarPtr(.HighPart), FILE_CURRENT)
95 ThrowIfFilePointerFunctionFailed(.LowPart)
96 End With
97 End Function
98 Override Function Length(s As FileStream) As QWord
99 Dim length = VarPtr(Length) As *ULARGE_INTEGER
100 length->LowPart = GetFileSize(s.Handle, VarPtr(length->HighPart))
101 ThrowIfFilePointerFunctionFailed(length->LowPart)
102 End Function
103 Override Sub SetLength(s As FileStream, value As QWord)
104 If s.CanWrite() Then
105 Dim current = s.Position()
106 Position(s, value)
107 Dim ret = SetEndOfFile(s.Handle)
108 If ret = FALSE Then
109 Detail.ThrowWinLastErrorIOException("FileStream.SetLength failed")
110 End If
111 Position(s, current)
112 End If
113 End Sub
114End Class
115
116/*!
117@brief シークできる実装(重複IO用)
118@date 2008/08/21
119@auther Egtra
120*/
121Class OverlappedSeekable
122 Inherits Seekable
123Public
124 Override Function Seek(s As FileStream, offset As Int64, origin As SeekOrigin) As Int64
125 Seek = Super.Seek(s, offset, origin)
126 offset = Position(s)
127 End Function
128 Override Sub Position(s As FileStream, value As QWord)
129 Super.Position(s, value)
130 offset = value
131 End Sub
132 Override Function Position(s As FileStream) As QWord
133 Position = offset
134 End Function
135Private
136 offset As QWord
137End Class
138
139'---------------------------------------
140
141/*!
142@brief 読み取り関数の集合
143@date 2008/08/21
144@auther Egtra
145*/
146Class ReadFunctions
147Public
148 Abstract Function CanRead() As Boolean
149 Abstract Function Read(s As FileStream, buffer As *Byte, offset As Long, count As Long) As Long
150 Abstract Function BeginRead(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
151 Abstract Function EndRead(s As FileStream, asyncResult As System.IAsyncResult) As Long
152End Class
153
154/*!
155@brief 読み取りできない実装
156@date 2008/08/21
157@auther Egtra
158*/
159Class Unreadable
160 Inherits ReadFunctions
161Public
162 Override Function CanRead() As Boolean
163 Return False
164 End Function
165
166 Override Function Read(s As FileStream, buffer As *Byte, offset As Long, count As Long) As Long
167 Throw New NotSupportedException("FileStream.Read")
168 End Function
169
170 Override Function BeginRead(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
171 Throw New NotSupportedException("FileStream.BeginRead")
172 End Function
173
174 Override Function EndRead(s As FileStream, asyncResult As System.IAsyncResult) As Long
175 Throw New NotSupportedException("FileStream.EndRead")
176 End Function
177End Class
178
179/*!
180@brief 読み取りできる実装
181@date 2008/08/21
182@auther Egtra
183*/
184Class Readable
185 Inherits ReadFunctions
186Public
187 Override Function CanRead() As Boolean
188 Return True
189 End Function
190 Override Function Read(s As FileStream, buffer As *Byte, offset As Long, count As Long) As Long
191 Dim readBytes As DWord
192 Dim ret = ReadFile(s.Handle, VarPtr(buffer[offset]), count As DWord, VarPtr(readBytes), ByVal NULL)
193 If ret = FALSE Then
194 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
195 End If
196 Read = readBytes As Long
197 End Function
198
199 Override Function BeginRead(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
200 BeginRead = ThreadPoolIo(ToMBStr("ReadFile"), s, buffer, offset, count, callback, state)
201 End Function
202
203 Override Function EndRead(s As FileStream, asyncResult As System.IAsyncResult) As Long
204 Dim ar = asyncResult As Detail.IAsyncStreamResult
205 EndRead = ar.WaitAndGetResult
206 End Function
207End Class
208
209/*!
210@brief 読み取りできる実装(重複IO用)
211@date 2008/08/21
212@auther Egtra
213*/
214Class OverlappedReadable
215 Inherits Readable
216Public
217 Override Function Read(s As FileStream, buffer As *Byte, offset As Long, count As Long) As Long
218 Read = EndRead(s, BeginRead(s, buffer, offset, count, Nothing, Nothing))
219 End Function
220
221 Override Function BeginRead(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
222 BeginRead = BeginOverlappedIo(ToMBStr("ReadFile"), s, buffer, offset, count, callback, state)
223 If s.CanSeek Then
224 s.Seek(count, SeekOrigin.Current)
225 End If
226 End Function
227End Class
228
229'---------------------------------------
230
231/*!
232@brief 書き込み関数の集合
233@date 2008/08/21
234@auther Egtra
235*/
236Class WriteFunctions
237Public
238 Abstract Function CanWrite() As Boolean
239 Abstract Sub Write(s As FileStream, buffer As *Byte, offset As Long, count As Long)
240 Abstract Function BeginWrite(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
241 Abstract Sub EndWrite(s As FileStream, asyncResult As System.IAsyncResult)
242End Class
243
244/*!
245@brief 書き込みできない実装
246@date 2008/08/21
247@auther Egtra
248*/
249Class Unwritable
250 Inherits WriteFunctions
251Public
252 Override Function CanWrite() As Boolean
253 Return False
254 End Function
255
256 Override Sub Write(s As FileStream, buffer As *Byte, offset As Long, count As Long)
257 Throw New NotSupportedException("FileStream.Write")
258 End Sub
259
260 Override Function BeginWrite(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
261 Throw New NotSupportedException("FileStream.BeginWrite")
262 End Function
263
264 Override Sub EndWrite(s As FileStream, asyncResult As System.IAsyncResult)
265 Throw New NotSupportedException("FileStream.EndWrite")
266 End Sub
267End Class
268
269/*!
270@brief 書き込みできる実装
271@date 2008/08/21
272@auther Egtra
273*/
274Class Writable
275 Inherits WriteFunctions
276Public
277 Override Function CanWrite() As Boolean
278 Return True
279 End Function
280
281 Override Sub Write(s As FileStream, buffer As *Byte, offset As Long, count As Long)
282 Dim readBytes As DWord
283 Dim ret = WriteFile(s.Handle, VarPtr(buffer[offset]), count As DWord, VarPtr(readBytes), ByVal NULL)
284 If ret = FALSE Then
285 Detail.ThrowWinLastErrorIOException("FileStream.Write: Failed to write.")
286 End If
287 End Sub
288
289 Override Function BeginWrite(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
290 BeginWrite = ThreadPoolIo(ToMBStr("WriteFile"), s, buffer, offset, count, callback, state)
291 End Function
292
293 Override Sub EndWrite(s As FileStream, asyncResult As System.IAsyncResult)
294 Dim ar = asyncResult As Detail.IAsyncStreamResult
295 ar.WaitAndGetResult()
296 End Sub
297End Class
298
299/*!
300@brief 書き込みできる実装(重複IO用)
301@date 2008/08/21
302@auther Egtra
303*/
304Class OverlappedWritable
305 Inherits Writable
306Public
307 Override Sub Write(s As FileStream, buffer As *Byte, offset As Long, count As Long)
308 EndWrite(s, BeginWrite(s, buffer, offset, count, Nothing, Nothing))
309 End Sub
310
311 Override Function BeginWrite(s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
312 BeginWrite = BeginOverlappedIo(ToMBStr("WriteFile"), s, buffer, offset, count, callback, state)
313 If s.CanSeek Then
314 s.Seek(count, SeekOrigin.Current)
315 End If
316 End Function
317End Class
318
319'---------------------------------------
320
321/*!
322@brief 重複IO実行開始
323@param[in] fn "ReadFile"か"WriteFile"または引数に互換性のあるkernel32の関数名
324@param[in] s 対象のストリーム
325@param[in,out] buffer 入出力先
326@param[in] offset buffer内で入出力を開始する位置
327@param[in] count 読み書きするバイト数
328@param[in] callback 完了したときに呼ばれるデリゲート
329@param[in] state IAsyncResultへの追加引数
330@return EndRead/Writeへの引き換えとなるIAsyncResult
331@date 2008/08/21
332@auther Egtra
333*/
334Function BeginOverlappedIo(fn As PCSTR, s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As Detail.AsyncStreamResult
335 Dim ioFile = GetProcAddress(GetModuleHandle("kernel32.dll"), fn) As Detail.PIOFile
336 BeginOverlappedIo = New Detail.AsyncStreamResult(s.Handle, state)
337 Dim pov = BeginOverlappedIo.PtrToOverlapped
338 Dim position = s.Position
339 pov->Offset = LODWORD(position)
340 pov->OffsetHigh = HIDWORD(position)
341 position += count
342 If ioFile(s.Handle, buffer + offset, count, 0, pov) Then
343 BeginOverlappedIo.SetCompletedSynchronously()
344 Else
345 Dim lastError = GetLastError()
346 If lastError = ERROR_IO_PENDING Then
347 If Not ActiveBasic.IsNothing(callback) Then
348 Dim d = New Detail.CallbackData
349 d.Callback = callback
350 d.Result = BeginOverlappedIo
351 Threading.ThreadPool.RegisterWaitForSingleObject(BeginOverlappedIo.AsyncWaitHandle, AddressOf(CallAsyncCallbackB), d)
352 End If
353 Exit Function
354 ElseIf lastError = ERROR_HANDLE_EOF Then
355 BeginOverlappedIo.SetCompletedSynchronously()
356 BeginOverlappedIo.Handle = 0
357 BeginOverlappedIo.Result = 0
358 Else
359 Detail.ThrowWinIOException("AsyncFileStream", lastError)
360 End If
361 End If
362 If Not ActiveBasic.IsNothing(callback) Then
363 Dim d = New Detail.CallbackData
364 d.Callback = callback
365 d.Result = BeginOverlappedIo
366 Threading.ThreadPool.QueueUserWorkItem(AddressOf(CallAsyncCallback), d)
367 End If
368End Function
369
370/*!
371@brief BeginOverlappedIoのコールバック補助
372@return EndRead/Writeへの引き換えとなるIAsyncResult
373@date 2008/08/21
374@auther Egtra
375*/
376Sub CallAsyncCallbackB(o As Object, b As Boolean)
377 CallAsyncCallback(o)
378End Sub
379
380/*!
381@brief BeginOverlappedIoのコールバック補助
382@return EndRead/Writeへの引き換えとなるIAsyncResult
383@date 2008/08/21
384@auther Egtra
385*/
386Sub CallAsyncCallback(o As Object)
387 Dim d = o As Detail.CallbackData
388 Dim c = d.Callback
389 c(d.Result)
390End Sub
391
392/*!
393@brief Stream用IAsyncResult拡張
394@date 2008/08/21
395@auther Egtra
396*/
397Interface IAsyncStreamResult
398 Inherits IAsyncResult
399 /*!
400 @brief 入出力完了まで待機する
401 @return 読み書きしたバイト数
402 */
403 Function WaitAndGetResult() As DWord
404End Interface
405
406/*!
407@brief IAsyncStreamResult実装用基底クラス
408@date 2008/08/21
409@auther Egtra
4102つの派生クラス、AsyncStreamResultとThreadPoolIoResultの共通部分
411*/
412Class AsyncStreamResultImplBase
413 Implements IAsyncStreamResult
414Protected
415 Sub AsyncStreamResultImplBase(state As Object)
416 Imports System.Threading
417 wait = New EventWaitHandle(False, EventResetMode.ManualReset)
418 s = state
419 End Sub
420Public
421 Virtual Function AsyncWaitHandle() As Threading.WaitHandle
422 AsyncWaitHandle = wait
423 End Function
424
425 Virtual Function CompletedSynchronously() As Boolean
426 End Function
427
428 Virtual Function IsCompleted() As Boolean
429 IsCompleted = AsyncWaitHandle.WaitOne(0)
430 End Function
431
432 Virtual Function AsyncState() As Object
433 AsyncState = s
434 End Function
435
436 Virtual Function WaitAndGetResult() As DWord
437 End Function
438
439 Function AsyncEventWaitHandle() As Threading.EventWaitHandle
440 AsyncEventWaitHandle = wait
441 End Function
442Private
443 wait As Threading.EventWaitHandle
444 s As Object
445End Class
446
447/*!
448@brief 重複IO用IAsyncStreamResult実装
449@date 2008/08/21
450@auther Egtra
451*/
452Class AsyncStreamResult
453 Inherits AsyncStreamResultImplBase
454Public
455 Sub AsyncStreamResult(handle As HANDLE, state As Object)
456 AsyncStreamResultImplBase(state)
457 h = handle
458 cs = False
459 overlapped.hEvent = AsyncWaitHandle.Handle
460 End Sub
461
462 Override Function CompletedSynchronously() As Boolean
463 CompletedSynchronously = cs
464 End Function
465
466 Sub SetCompletedSynchronously()
467 cs = True
468 wait.Set()
469 End Sub
470
471 Override Function WaitAndGetResult() As DWord
472 If h <> 0 Then
473 If GetOverlappedResult(h, overlapped, result, TRUE) = FALSE Then
474 Detail.ThrowWinLastErrorIOException("FileStream.EndRead/Write")
475 End If
476 h = 0
477 End If
478 WaitAndGetResult = result
479 End Function
480
481 Function PtrToOverlapped() As *OVERLAPPED
482 PtrToOverlapped = VarPtr(overlapped)
483 End Function
484
485 Sub Handle(handle As HANDLE)
486 h = handle
487 End Sub
488
489 '同期IO用
490 Sub Result(res As DWord)
491 result = res
492 End Sub
493Private
494 overlapped As OVERLAPPED
495 h As HANDLE
496 result As DWord
497 cs As Boolean
498End Class
499
500/*!
501@brief ThreadPoolIo用IAsyncStreamResult実装
502@date 2008/08/21
503@auther Egtra
504ThreadPoolIo関数も参照
505*/
506Class ThreadPoolIoResult
507 Inherits AsyncStreamResultImplBase
508Public
509 Sub ThreadPoolIoResult(state As Object)
510 AsyncStreamResultImplBase(state)
511 End Sub
512
513 Override Function CompletedSynchronously() As Boolean
514 CompletedSynchronously = False
515 End Function
516
517 Override Function WaitAndGetResult() As DWord
518 AsyncWaitHandle.WaitOne()
519 If Not ActiveBasic.IsNothing(ex) Then
520 Throw ex
521 End If
522 WaitAndGetResult = Result
523 End Function
524
525 Sub SetException(e As Exception)
526 ex = e
527 End Sub
528
529 Result As DWord
530Private
531 ex As Exception
532End Class
533
534/*!
535@brief Stream用同期IAsyncStreamResult実装
536@date 2008/08/21
537@auther Egtra
538StreamでのBeginRead/Writeの実装は、常にBegin内部で同期的に処理するというもの。これはそれ用の実装。
539*/
540Class SyncStreamResultImpl
541 Implements IAsyncStreamResult
542Public
543 Sub SyncStreamResultImpl(result As DWord, state As Object)
544 Imports System.Threading
545 wait = New EventWaitHandle(False, EventResetMode.ManualReset)
546 s = state
547 End Sub
548
549 Virtual Function AsyncWaitHandle() As Threading.WaitHandle
550 Imports System.Threading
551 If ActiveBasic.IsNothing(wait) Then
552 wait = New EventWaitHandle(True, EventResetMode.ManualReset)
553 End If
554 AsyncWaitHandle = wait
555 End Function
556
557 Virtual Function CompletedSynchronously() As Boolean
558 CompletedSynchronously = True
559 End Function
560
561 Virtual Function IsCompleted() As Boolean
562 IsCompleted = True
563 End Function
564
565 Virtual Function AsyncState() As Object
566 AsyncState = s
567 End Function
568
569 Virtual Function WaitAndGetResult() As DWord
570 WaitAndGetResult = res
571 End Function
572
573 Function AsyncEventWaitHandle() As Threading.EventWaitHandle
574 AsyncEventWaitHandle = wait
575 End Function
576Private
577 s As Object
578 res As DWord
579
580 Static wait = Nothing As Threading.EventWaitHandle
581End Class
582
583/*!
584@brief ReadFile/WriteFileのプロトタイプに一致する関数へのポインタ
585@date 2008/08/21
586@auther Egtra
587*/
588TypeDef PIOFile = *Function(h As HANDLE, buf As VoidPtr, bytes As DWord, result As *DWord, ov As *OVERLAPPED) As BOOL
589
590/*!
591@brief BeginOverlappedIoとCallAsyncCallbackとの間で受け渡されるデータの集まり
592@date 2008/08/21
593@auther Egtra
594*/
595Class CallbackData
596Public
597 Callback As AsyncCallback
598 Result As IAsyncResult
599End Class
600
601'---------------------------------------
602
603/*!
604@brief スレッドプールによる非同期IO
605@date 2008/08/21
606@param[in] fn "ReadFile"か"WriteFile"または引数に互換性のあるkernel32の関数名
607@param[in] s 対象のストリーム
608@param[in,out] buffer 入出力先
609@param[in] offset buffer内で入出力を開始する位置
610@param[in] count 読み書きするバイト数
611@param[in] callback 完了したときに呼ばれるデリゲート
612@param[in] state IAsyncResultへの追加引数
613@return EndRead/Writeへの引き換えとなるIAsyncResult
614@auther Egtra
615OVERLAPPED指定無しで開いたファイルの非同期関数用
616*/
617Function ThreadPoolIo(ioType As PCSTR, s As FileStream, buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
618 Dim result = New ThreadPoolIoResult(state)
619 ThreadPoolIo = result
620 Dim d = New ThreadPoolIoData
621 With d
622 .IoType = ioType
623 .Handle = s.Handle
624 .Result = result
625 .Buffer = buffer + offset
626 .Size = count As DWord
627 End With
628 Threading.ThreadPool.QueueUserWorkItem(AddressOf(ThreadIo), d)
629End Function
630
631/*!
632@brief ThreadPoolIo補助で実際に入出力関数を呼ぶ
633@date 2008/08/21
634@auther Egtra
635*/
636Sub ThreadIo(o As Object)
637 Dim d = o As ThreadPoolIoData
638 With d
639 Dim ioFile = GetProcAddress(GetModuleHandle("kernel32.dll"), .IoType) As Detail.PIOFile
640 If ioFile(.Handle, .Buffer, .Size, VarPtr(.Result.Result), 0) = FALSE Then
641 .Result.SetException(Detail.GetWinLastErrorIOException("FileStream.BeginRead/Write"))
642 End If
643 d.Result.AsyncEventWaitHandle.Set()
644 If Not ActiveBasic.IsNothing(.Callback) Then
645 Dim c = .Callback
646 c(.Result)
647 End If
648 End With
649End Sub
650
651/*!
652@brief ThreadPoolIoとThreadIoとの間で受け渡すデータの集まり
653@date 2008/08/21
654@auther Egtra
655*/
656Class ThreadPoolIoData
657Public
658 IoType As PCSTR
659 Handle As HANDLE
660 Result As ThreadPoolIoResult
661 Callback As AsyncCallback
662 Buffer As *Byte
663 Size As DWord
664End Class
665
666End Namespace
667End Namespace
668End Namespace
Note: See TracBrowser for help on using the repository browser.