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

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

StreamReaderの完成。StringReaderの追加。
Consoleの追加(現在入力関係の一部のみ)。

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