source: trunk/Include/Classes/System/IO/FileStream.ab@ 430

Last change on this file since 430 was 430, checked in by NoWest, 16 years ago

CreateWaitHandleメソッドをManualResetEventを返すように実装。

File size: 13.1 KB
Line 
1Namespace System
2Namespace IO
3
4/* ほんとはmiscに入れるかかファイルを分けたほうがいいかもしれないが一先ず実装 */
5Enum FileOptions
6 None = 0
7 Asynchronous = FILE_FLAG_OVERLAPPED
8 DeleteOnClose = FILE_FLAG_DELETE_ON_CLOSE
9 Encrypted = FILE_ATTRIBUTE_ENCRYPTED
10 RandomAccess = FILE_FLAG_RANDOM_ACCESS
11 SequentialScan = FILE_FLAG_SEQUENTIAL_SCAN
12 WriteThrough = FILE_FLAG_WRITE_THROUGH
13End Enum
14
15Class FileStream
16 Inherits Stream
17
18 handle As HANDLE
19
20 /*
21 ファイルハンドルからこれらを取得できれば、これらは入らないが
22 今のところは不明なので自前で実装するしかない
23 */
24 filePath As String
25 fileMode As DWord
26 fileAccess As DWord
27 fileShare As DWord
28 fileOptions As DWord
29
30 offset As QWord 'オーバーラップドIO用
31
32Public
33 /* コンストラクタ.NETと同じように実装は難しい、一先ず動くものを実装したが変更が必要だと思う */
34 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
35 Dim ac As DWord
36 Dim mo As DWord
37 Dim sh As DWord
38 Dim op As DWord
39
40 Select Case access
41 Case FileAccess.Read
42 ac=GENERIC_READ
43 Case FileAccess.ReadWrite
44 ac=GENERIC_READ or GENERIC_WRITE
45 Case FileAccess.Write
46 ac=GENERIC_WRITE
47 End Select
48
49 Select Case share
50 Case FileShare.DeleteFile
51 sh=FILE_SHARE_DELETE
52 Case FileShare.None
53 sh=0
54 Case FileShare.Read
55 sh=FILE_SHARE_READ
56 Case FileShare.ReadWrite
57 sh=FILE_SHARE_READ or FILE_SHARE_WRITE
58 Case FileShare.Write
59 sh=FILE_SHARE_WRITE
60 End Select
61
62 Select Case mode
63 Case FileMode.Append
64 mo=OPEN_ALWAYS
65 Case FileMode.Create
66 mo=CREATE_ALWAYS
67 Case FileMode.CreateNew
68 mo=CREATE_NEW
69 Case FileMode.Open
70 mo=OPEN_EXISTING
71 Case FileMode.OpenOrCreate
72 mo=OPEN_ALWAYS
73 Case FileMode.Truncate
74 mo=TRUNCATE_EXISTING
75 End Select
76
77 op = options As DWord
78' If (Environment.OSVersion.Platform As DWord) <> (PlatformID.Win32NT As DWord) Then 'ToDo: なぜかアクセス違反になる
79 op And= Not FILE_FLAG_OVERLAPPED
80' End If
81
82 This.handle=CreateFile(ToTCStr(path),ac,sh,ByVal NULL,mo,op,0)
83 If This.handle=INVALID_HANDLE_VALUE Then
84 'エラー処理
85 'Throw ArgumentException
86 'Throw IOException
87 'Throw System.IO.FileNotFoundException
88 This.handle=0
89 Beep(220,500)
90 Exit Sub
91 End If
92
93 This.filePath = path
94 This.fileMode = mo
95 This.fileAccess = ac
96 This.fileShare = sh
97 This.fileOptions = op
98 This.offset = 0
99 End Sub
100 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare)
101 This.FileStream(path,mode,access,share,FileOptions.None)
102 End Sub
103 Sub FileStream(path As String, mode As FileMode, access As FileAccess)
104 This.FileStream(path,mode,access,FileShare.None,FileOptions.None)
105 End Sub
106 Sub FileStream(path As String, mode As FileMode)
107 Dim access As FileAccess
108 Select Case mode
109 Case FileMode.Append
110 access=FileAccess.Write
111 Case FileMode.Create
112 access=FileAccess.ReadWrite
113 Case FileMode.CreateNew
114 access=FileAccess.ReadWrite
115 Case FileMode.Open
116 access=FileAccess.ReadWrite
117 Case FileMode.OpenOrCreate
118 access=FileAccess.ReadWrite
119 Case FileMode.Truncate
120 access=FileAccess.Write
121 End Select
122 This.FileStream(path,mode,access,FileShare.None,FileOptions.None)
123 End Sub
124Public
125 /*!
126 @brief ファイルが読み込みに対応しているかを返す
127 */
128 Override Function CanRead() As Boolean
129 If This.fileAccess And GENERIC_READ Then
130 Return True
131 Else
132 Return False
133 End If
134 End Function
135
136 /*!
137 @brief ファイルがシークに対応しているかを返す
138 */
139 Override Function CanSeek() As Boolean
140 If GetFileType(This.handle)=FILE_TYPE_DISK Then
141 Return True
142 Else
143 Return False
144 End If
145 End Function
146
147' Override Function CanTimeout() As Boolean
148' /* ファイルがタイムアウトに対応しているかを返す */
149' Return False /*今のところ対応していないのでFalse*/
150' End Function*/
151
152 /*!
153 @brief ファイルが書き込みに対応しているかを返す
154 */
155 Override Function CanWrite() As Boolean
156 If This.fileAccess And GENERIC_WRITE Then
157 Return True
158 Else
159 Return False
160 End If
161 End Function
162
163 /*Handle*/
164
165 /*!
166 @brief ファイルが非同期操作に対応しているかを返す
167 */
168 Function IsAsync() As Boolean
169 If This.fileOptions And FILE_FLAG_OVERLAPPED /*FileOptions.Asynchronous*/ Then
170 Return True
171 Else
172 Return False
173 End If
174 End Function
175
176 Override Function Length() As Int64
177 disposedCheck()
178 If This.CanSeek() Then
179 Dim length = VarPtr(Length) As *ULARGE_INTEGER
180 length->LowPart = GetFileSize(This.handle, VarPtr(length->HighPart))
181 If LODWORD(Length) = INVALID_FILE_SIZE Then
182 Dim error = GetLastError()
183 If error <> NO_ERROR Then
184' Detail.ThrowWinIOException("FileStream.Read: Failed to read.", error)
185 End If
186 End If
187
188 If Length < 0 Then
189 Debug 'Throw OverflowException
190 End If
191 End If
192 End Function
193
194 Function Name() As String
195 Return This.filePath
196 End Function
197
198 Override Sub Position(value As Int64)
199 disposedCheck()
200 If This.CanSeek() Then
201 If This.IsAsync() Then
202 offset = value As QWord
203 Else
204 Dim position As LARGE_INTEGER
205 position.LowPart=LODWORD(value)
206 position.HighPart=HIDWORD(value)
207 SetFilePointer(This.handle,position.LowPart,VarPtr(position.HighPart) As *DWord,FILE_BEGIN)
208 End If
209 End If
210 End Sub
211 Override Function Position() As Int64
212 disposedCheck()
213 If This.CanSeek() Then
214 If This.IsAsync() Then
215 Return offset As Int64
216 Else
217 Dim position As LARGE_INTEGER
218 ZeroMemory(VarPtr(position),SizeOf(LARGE_INTEGER))
219 position.LowPart=SetFilePointer(This.handle,position.LowPart,VarPtr(position.HighPart) As *DWord,FILE_CURRENT)
220 Return MAKEQWORD(position.LowPart,position.HighPart) As Int64
221 End If
222 End If
223 End Function
224
225/* Override Sub ReadTimeout(value As Long)
226 'TODO
227 End Sub
228 Override Function ReadTimeout() As Long
229 'TODO
230 End Function*/
231
232 /* Safe~Handle系の実装は要相談!! */
233/* Function SafeFileHandle() As SafeFileHandle
234 End Function*/
235
236 Override Sub WriteTimeout(value As Long)
237 'TODO
238 End Sub
239 Override Function WriteTimeout() As Long
240 'TODO
241 End Function
242
243
244Public
245 Override Function BeginRead(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
246 If This.IsAsync() Then
247 Else
248 Read(buffer,offset,count)
249 End If
250 End Function
251
252 Override Function BeginWrite(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
253 If This.IsAsync() Then
254 Else
255 Write(buffer,offset,count)
256 End If
257 End Function
258
259/* CreateObjRef*/
260
261 Override Sub Dispose(disposing As Boolean)
262 Flush()
263 CloseHandle(InterlockedExchangePointer(VarPtr(This.handle),NULL))
264 End Sub
265
266 Override Function EndRead(asyncResult As System.IAsyncResult) As Long
267 'TODO
268 End Function
269
270 Override Sub EndWrite(asyncResult As System.IAsyncResult)
271 'TODO
272 End Sub
273
274/* Equals*/
275
276 Override Sub Flush()
277 disposedCheck()
278 Dim ret = FlushFileBuffers(This.handle)
279 If ret = FALSE Then
280' Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
281 End If
282 End Sub
283
284/* Function GetAccessControl() As FileSecurity
285 FileSecurityの実装がまだできてない。
286 End Function*/
287
288/* GetLifetimeService*/
289
290/* Override Function GetType() As TypeInfo
291 Return Super.GetType()
292 End Function*/
293
294/* InitializeLifetimeService*/
295
296 Sub Lock(position As Int64, length As Int64)
297 disposedCheck()
298 If position < 0 Then
299 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.Int64(position), "position")
300 ElseIf length < 0 Then
301 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.Int64(length), "length")
302 End If
303 LockFile(handle, LODWORD(position As QWord), HIDWORD(position As QWord),
304 LODWORD(length As QWord), HIDWORD(length As QWord))
305 End Sub
306
307 Override Function Read(buffer As *Byte, offset As Long, count As Long) As Long
308 disposedCheck()
309 If buffer = 0 Then
310 Throw New ArgumentNullException("FileStream.Read: An argument is null value.", "buffer")
311 ElseIf Not This.CanRead() Then
312 Throw New NotSupportedException("FileStream.Read: This stream is not readable.")
313 End If
314
315 Dim ret As BOOL
316 Dim readBytes As DWord
317 If This.IsAsync() Then
318 Dim overlapped As OVERLAPPED
319 SetQWord(VarPtr(overlapped.Offset), offset)
320 overlapped.hEvent = CreateEvent(0, TRUE, FALSE, 0)
321 If overlapped.hEvent = 0 Then
322 Throw New OutOfMemoryException("FileStream.Read: Failed to create an event object.")
323 End If
324 Try
325 ret = ReadFile(This.handle, VarPtr(buffer[offset]), count, 0, overlapped)
326 If ret = FALSE Then
327 Dim error = GetLastError()
328 If error <> ERROR_IO_PENDING Then
329 Detail.ThrowWinIOException("FileStream.Read: Failed to read.", error)
330 End If
331 End If
332 ret = GetOverlappedResult(This.handle, overlapped, readBytes, TRUE)
333 If ret = FALSE Then
334 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
335 End If
336 offset += Read
337 Finally
338 CloseHandle(overlapped.hEvent)
339 End Try
340 Else
341 ret = ReadFile(This.handle,VarPtr(buffer[offset]),count,VarPtr(readBytes),ByVal NULL)
342 If ret = FALSE Then
343 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
344 End If
345 End If
346 Read = readBytes As Long
347 End Function
348
349 /*!
350 @brief ストリームの現在位置を移動させる。
351 @param[in] offset originからの移動量
352 @param[in] origin 移動の基準位置
353 @return 移動後の新しい現在位置
354 @exception DisposedException 既にストリームが閉じられている場合
355 @exception ArgumentException 移動後の位置が負の位置(ファイル先頭より手前)になる場合
356 @exception IOException その他エラーが発生した場合
357 */
358 Override Function Seek(offset As Int64, origin As SeekOrigin) As Int64
359 disposedCheck()
360 If This.CanSeek() Then
361 If This.IsAsync() Then
362 Select Case origin
363 Case SeekOrigin.Begin
364 This.offset = offset
365 Case SeekOrigin.Current
366 This.offset += offset
367 Case SeekOrigin.End
368 This.offset = This.Length + offset
369 End Select
370 Seek = This.offset As Int64
371 If Seek < 0 Then
372' Throw ArgumentException("FileStream.Seek: Cannot seek to negative offset.")
373 End If
374 Else
375 Dim seek = VarPtr(offset) As *ULARGE_INTEGER
376 Dim ret = SetFilePointer(This.handle, seek->LowPart, VarPtr(seek->HighPart), origin As DWord)
377 If ret = INVALID_SET_FILE_POINTER Then
378 Dim error = GetLastError()
379 If error = ERROR_NEGATIVE_SEEK Then
380' Throw ArgumentException("FileStream.Seek: Cannot seek to negative offset.")
381 ElseIf error <> NO_ERROR Then
382' Throw Detail.ThrowWinIOException("FileStream.Seek: Failed to seek.", error)
383 End If
384 End If
385 seek->LowPart = ret
386 Seek = offset
387 End If
388 End If
389 End Function
390
391/* Sub SetAccessControl(fileSecurity As FileSecurity)
392 FileSecurityの実装がまだできてない。
393 End Sub*/
394
395 Override Sub SetLength(value As Int64)
396 disposedCheck()
397 If This.CanWrite() and This.CanSeek() Then
398 If This.IsAsync() Then
399 Else
400 Dim current = This.Position()
401 This.Position(value)
402 Dim ret = SetEndOfFile(This.handle)
403 If ret = FALSE Then
404 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
405 End If
406 Position = current
407 End If
408 End If
409 End Sub
410
411/* Synchronized*/
412
413 Override Function ToString() As String
414 Return This.Name()
415 End Function
416
417 Sub Unlock(position As Int64, length As Int64)
418 disposedCheck()
419 If position < 0 Then
420 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.Int64(position), "position")
421 ElseIf length < 0 Then
422 Throw New ArgumentOutOfRangeException("FileStream.Lock: An argument is negative value.", New System.Int64(length), "length")
423 End If
424 Dim ret = UnlockFile(handle, LODWORD(position As QWord), HIDWORD(position As QWord),
425 LODWORD(length As QWord), HIDWORD(length As QWord))
426 If ret = FALSE Then
427 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
428 End If
429 End Sub
430
431 Override Sub Write(buffer As *Byte, offset As Long, count As Long)
432 disposedCheck()
433 If This.CanWrite() Then
434 Dim writeBytes As DWord
435 If This.IsAsync() Then
436 Dim overlapped As OVERLAPPED
437 SetQWord(VarPtr(overlapped.Offset), offset)
438 overlapped.hEvent = CreateEvent(0, TRUE, FALSE, 0)
439 Dim ret = WriteFile(This.handle, VarPtr(buffer[offset]), count, 0, overlapped)
440 If ret <> FALSE Or GetLastError() = ERROR_IO_PENDING Then
441 GetOverlappedResult(This.handle, overlapped, writeBytes, TRUE)
442 End If
443 offset += writeBytes
444 CloseHandle(overlapped.hEvent)
445 Else
446 WriteFile(This.handle, VarPtr(buffer[offset]), count, VarPtr(writeBytes), ByVal NULL)
447 End If
448 End If
449 End Sub
450
451Protected
452 Override Function CreateWaitHandle() As System.Threading.WaitHandle
453 Return New System.Threading.AutoResetEvent(False)
454 End Function
455
456Private
457 Sub disposedCheck()
458 If handle = 0 Then
459' Throw ObjectDisposedException("FileStream: This stream has closed.")
460 End If
461 End Sub
462
463End Class
464
465
466End Namespace
467End Namespace
Note: See TracBrowser for help on using the repository browser.