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

Last change on this file since 560 was 560, checked in by dai, 16 years ago

#183への対応。コンストラクタ、デストラクタが直接呼び出された場合はエラーとして扱うようにした。
(64bit版は後ほどコミットします)

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