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

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

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

File size: 11.8 KB
RevLine 
[605]1'Classes/System/IO/FileStream.ab
2
[271]3Namespace System
4Namespace IO
[256]5
[605]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*/
[256]17
[105]18Class FileStream
[256]19 Inherits Stream
[605]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
[256]55
[605]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
[435]59 Throw New ArgumentNullException("path")
60 ElseIf path.Length = 0 Then
[605]61 Throw New ArgumentException("path.Length = 0")
[435]62 End If
[432]63 Dim sh = share As DWord
64 Dim mo = mode As DWord
65 Dim op = options As DWord
[256]66
[605]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
[256]80 'エラー処理
81 'Throw ArgumentException
82 'Throw IOException
[605]83 'Throw System.IO.FileNotFoundException
84 handle = 0
[435]85 Detail.ThrowWinLastErrorIOException("Failed to open/create file.")
[256]86 End If
[605]87
88 filePath = path
[256]89
[605]90 If mode = FileMode.Append Then
[474]91 Seek(0, SeekOrigin.End)
92 End If
[256]93 End Sub
[560]94
[605]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
[560]123Public
[605]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 */
[560]145 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
[605]146 initWithOpen(path, mode, access, share, options)
[560]147 End Sub
[605]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 */
[260]172 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare)
[605]173 initWithOpen(path,mode,access,share,FileOptions.None)
[260]174 End Sub
[605]175 /*!
176 @brief ファイルを開く。
177 @param[in] path ファイルパス
178 @param[in] mode 開き方
179 @param[in] access ファイルアクセスの指定
180 */
[260]181 Sub FileStream(path As String, mode As FileMode, access As FileAccess)
[605]182 initWithOpen(path,mode,access,FileShare.None,FileOptions.None)
[260]183 End Sub
[605]184 /*!
185 @brief ファイルを開く。
186 @param[in] path ファイルパス
187 @param[in] mode 開き方
188 */
[256]189 Sub FileStream(path As String, mode As FileMode)
[260]190 Dim access As FileAccess
[256]191 Select Case mode
192 Case FileMode.Append
[260]193 access=FileAccess.Write
[256]194 Case FileMode.Create
[260]195 access=FileAccess.ReadWrite
[256]196 Case FileMode.CreateNew
[260]197 access=FileAccess.ReadWrite
[256]198 Case FileMode.Open
[260]199 access=FileAccess.ReadWrite
[256]200 Case FileMode.OpenOrCreate
[260]201 access=FileAccess.ReadWrite
[256]202 Case FileMode.Truncate
[260]203 access=FileAccess.Write
[256]204 End Select
[605]205 initWithOpen(path,mode,access,FileShare.None,FileOptions.None)
[256]206 End Sub
[605]207 /*!
208 @brief 既存ハンドルを基にストリームを作る。
209 @param[in] h ハンドル
210 @param[in] access ファイルアクセスの指定
211 @param[in] owns 所有権を保持するかどうか(TrueならDispose時に基のハンドルも閉じる)
212 @param[in] isAsync 重複IOを使用するかどうか
[432]213 @date 2008/02/26
214 @auther Egtra
[605]215 @todo SafeFileHandle版に置き換えること
[432]216 */
[605]217 Sub FileStream(h As HANDLE, access As FileAccess, owns = True As Boolean, isAsync = False As Boolean)
[432]218 handle = h
[605]219 initialize(access, owns, isAsync)
[432]220 End Sub
[256]221Public
[391]222 /*!
223 @brief ファイルが読み込みに対応しているかを返す
224 */
[256]225 Override Function CanRead() As Boolean
[605]226 Return readFn.CanRead
[256]227 End Function
228
[391]229 /*!
230 @brief ファイルがシークに対応しているかを返す
231 */
[256]232 Override Function CanSeek() As Boolean
[605]233 Return seekFn.CanSeek
[256]234 End Function
235
[391]236 /*!
237 @brief ファイルが書き込みに対応しているかを返す
238 */
[256]239 Override Function CanWrite() As Boolean
[605]240 Return writeFn.CanWrite
[256]241 End Function
242
[605]243 /*!
244 @brief 保持しているハンドルを返す
245 */
[552]246 Function Handle() As HANDLE
247 Return handle
248 End Function
[256]249
[605]250 Override Function Length() As QWord
[391]251 disposedCheck()
[605]252 Length = seekFn.Length(This)
[256]253 End Function
254
255 Function Name() As String
[388]256 Return This.filePath
[256]257 End Function
[605]258
259 Override Sub Position(value As QWord)
[391]260 disposedCheck()
[605]261 seekFn.Position(This, value)
[256]262 End Sub
[605]263 Override Function Position() As QWord
[391]264 disposedCheck()
[605]265 Position = seekFn.Position(This)
[256]266 End Function
267
[605]268Public
[256]269 /* Safe~Handle系の実装は要相談!! */
270/* Function SafeFileHandle() As SafeFileHandle
271 End Function*/
272
273Public
[348]274 Override Function BeginRead(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
[605]275 disposedCheck()
276 If buffer = 0 Then
277 Throw New ArgumentNullException("FileStream.BeginRead", "buffer")
[336]278 End If
[605]279 BeginRead = readFn.BeginRead(This, buffer, offset, count, callback, state)
[256]280 End Function
281
[348]282 Override Function BeginWrite(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
[605]283 disposedCheck()
284 If buffer = 0 Then
285 Throw New ArgumentNullException("FileStream.BeginWrite", "buffer")
[336]286 End If
[605]287 BeginWrite = writeFn.BeginWrite(This, buffer, offset, count, callback, state)
[256]288 End Function
289
[388]290 Override Function EndRead(asyncResult As System.IAsyncResult) As Long
[605]291 disposedCheck()
292 EndRead = readFn.EndRead(This, asyncResult)
[339]293 End Function
[256]294
[388]295 Override Sub EndWrite(asyncResult As System.IAsyncResult)
[605]296 disposedCheck()
297 writeFn.EndWrite(This, asyncResult)
[349]298 End Sub
[256]299
300 Override Sub Flush()
[391]301 disposedCheck()
302 Dim ret = FlushFileBuffers(This.handle)
303 If ret = FALSE Then
[605]304 Detail.ThrowWinLastErrorIOException("FileStream.Flush: Failed to flush.")
[391]305 End If
[256]306 End Sub
307
308/* Function GetAccessControl() As FileSecurity
309 FileSecurityの実装がまだできてない。
310 End Function*/
311
[605]312 Sub Lock(position As QWord, length As QWord)
[391]313 disposedCheck()
[388]314 If position < 0 Then
[605]315 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.UInt64(position), "position")
[388]316 ElseIf length < 0 Then
[605]317 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.UInt64(length), "length")
[388]318 End If
[605]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
[256]322 End Sub
323
[426]324 Override Function Read(buffer As *Byte, offset As Long, count As Long) As Long
[391]325 disposedCheck()
326 If buffer = 0 Then
[605]327 Throw New ArgumentNullException("FileStream.Read", "buffer")
[391]328 End If
[605]329 Read = readFn.Read(This, buffer, offset, count)
[256]330 End Function
331
[391]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()
[605]343 Seek = seekFn.Seek(This, offset, origin)
[256]344 End Function
345
346/* Sub SetAccessControl(fileSecurity As FileSecurity)
347 FileSecurityの実装がまだできてない。
348 End Sub*/
349
[605]350 Override Sub SetLength(value As QWord)
[391]351 disposedCheck()
[605]352 seekFn.SetLength(This, value)
[256]353 End Sub
354
355 Override Function ToString() As String
[336]356 Return This.Name()
[256]357 End Function
358
[605]359 Sub Unlock(position As QWord, length As QWord)
[391]360 disposedCheck()
[605]361 Dim ret = UnlockFile(handle, LODWORD(position), HIDWORD(position), LODWORD(length), HIDWORD(length))
[391]362 If ret = FALSE Then
[605]363 Detail.ThrowWinLastErrorIOException("FileStream.Unlock failed")
[391]364 End If
[256]365 End Sub
366
[337]367 Override Sub Write(buffer As *Byte, offset As Long, count As Long)
[391]368 disposedCheck()
[605]369 If buffer = 0 Then
370 Throw New ArgumentNullException("FileStream.Write", "buffer")
[256]371 End If
[605]372 writeFn.Write(This, buffer, offset, count)
[256]373 End Sub
374
375Protected
[432]376 Override Sub Dispose(disposing As Boolean)
377 If handle <> 0 Then
[439]378 CloseHandle(InterlockedExchangePointer(ByVal VarPtr(handle), NULL))
[432]379 End If
380 End Sub
381
[391]382 Sub disposedCheck()
383 If handle = 0 Then
[605]384 Throw New ObjectDisposedException("FileStream: This stream has already closed.")
[391]385 End If
386 End Sub
387
[605]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
[105]395End Class
[271]396
397End Namespace
398End Namespace
Note: See TracBrowser for help on using the repository browser.