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
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
33Public
34 /* コンストラクタ.NETと同じように実装は難しい、一先ず動くものを実装したが変更が必要だと思う */
35 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare, options As FileOptions)
36 Dim ac = access As DWord
37 Dim sh = share As DWord
38 Dim mo = mode As DWord
39 Dim op = options As DWord
40' If (Environment.OSVersion.Platform As DWord) <> (PlatformID.Win32NT As DWord) Then 'ToDo: なぜかアクセス違反になる
41 op And= Not FILE_FLAG_OVERLAPPED
42' End If
43
44 This.handle=CreateFile(ToTCStr(path),ac,sh,ByVal NULL,mo,op,0)
45 If This.handle=INVALID_HANDLE_VALUE Then
46 'エラー処理
47 'Throw ArgumentException
48 'Throw IOException
49 'Throw System.IO.FileNotFoundException
50 This.handle=0
51 Beep(220,500)
52 Exit Sub
53 End If
54
55 This.filePath = path
56 This.fileMode = mo
57 This.fileAccess = ac
58 This.fileShare = sh
59 This.fileOptions = op
60 This.offset = 0
61 This.ownsHandle = True
62 End Sub
63 Sub FileStream(path As String, mode As FileMode, access As FileAccess, share As FileShare)
64 This.FileStream(path,mode,access,share,FileOptions.None)
65 End Sub
66 Sub FileStream(path As String, mode As FileMode, access As FileAccess)
67 This.FileStream(path,mode,access,FileShare.None,FileOptions.None)
68 End Sub
69 Sub FileStream(path As String, mode As FileMode)
70 Dim access As FileAccess
71 Select Case mode
72 Case FileMode.Append
73 access=FileAccess.Write
74 Case FileMode.Create
75 access=FileAccess.ReadWrite
76 Case FileMode.CreateNew
77 access=FileAccess.ReadWrite
78 Case FileMode.Open
79 access=FileAccess.ReadWrite
80 Case FileMode.OpenOrCreate
81 access=FileAccess.ReadWrite
82 Case FileMode.Truncate
83 access=FileAccess.Write
84 End Select
85 This.FileStream(path,mode,access,FileShare.None,FileOptions.None)
86 End Sub
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
98Public
99 /*!
100 @brief ファイルが読み込みに対応しているかを返す
101 */
102 Override Function CanRead() As Boolean
103 If This.fileAccess And GENERIC_READ Then
104 Return True
105 Else
106 Return False
107 End If
108 End Function
109
110 /*!
111 @brief ファイルがシークに対応しているかを返す
112 */
113 Override Function CanSeek() As Boolean
114 If GetFileType(This.handle)=FILE_TYPE_DISK Then
115 Return True
116 Else
117 Return False
118 End If
119 End Function
120
121' Override Function CanTimeout() As Boolean
122' /* ファイルがタイムアウトに対応しているかを返す */
123' Return False /*今のところ対応していないのでFalse*/
124' End Function*/
125
126 /*!
127 @brief ファイルが書き込みに対応しているかを返す
128 */
129 Override Function CanWrite() As Boolean
130 If This.fileAccess And GENERIC_WRITE Then
131 Return True
132 Else
133 Return False
134 End If
135 End Function
136
137 /*Handle*/
138
139 /*!
140 @brief ファイルが非同期操作に対応しているかを返す
141 */
142 Function IsAsync() As Boolean
143 If This.fileOptions And FILE_FLAG_OVERLAPPED /*FileOptions.Asynchronous*/ Then
144 Return True
145 Else
146 Return False
147 End If
148 End Function
149
150 Override Function Length() As Int64
151 disposedCheck()
152 If This.CanSeek() Then
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
165 End If
166 End Function
167
168 Function Name() As String
169 Return This.filePath
170 End Function
171
172 Override Sub Position(value As Int64)
173 disposedCheck()
174 If This.CanSeek() Then
175 If This.IsAsync() Then
176 offset = value As QWord
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
183 End If
184 End Sub
185 Override Function Position() As Int64
186 disposedCheck()
187 If This.CanSeek() Then
188 If This.IsAsync() Then
189 Return offset As Int64
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)
194 Return MAKEQWORD(position.LowPart,position.HighPart) As Int64
195 End If
196 End If
197 End Function
198
199/* Override Sub ReadTimeout(value As Long)
200 'TODO
201 End Sub
202 Override Function ReadTimeout() As Long
203 'TODO
204 End Function*/
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
219 Override Function BeginRead(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
220 If This.IsAsync() Then
221 Else
222 Read(buffer,offset,count)
223 End If
224 End Function
225
226 Override Function BeginWrite(buffer As *Byte, offset As Long, count As Long, callback As AsyncCallback, state As Object) As System.IAsyncResult
227 If This.IsAsync() Then
228 Else
229 Write(buffer,offset,count)
230 End If
231 End Function
232
233/* CreateObjRef*/
234
235 Override Function EndRead(asyncResult As System.IAsyncResult) As Long
236 'TODO
237 End Function
238
239 Override Sub EndWrite(asyncResult As System.IAsyncResult)
240 'TODO
241 End Sub
242
243/* Equals*/
244
245 Override Sub Flush()
246 disposedCheck()
247 Dim ret = FlushFileBuffers(This.handle)
248 If ret = FALSE Then
249' Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
250 End If
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)
266 disposedCheck()
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))
274 End Sub
275
276 Override Function Read(buffer As *Byte, offset As Long, count As Long) As Long
277 disposedCheck()
278 If buffer = 0 Then
279 Throw New ArgumentNullException("FileStream.Read: An argument is null value.", "buffer")
280 ElseIf Not This.CanRead() Then
281 Throw New NotSupportedException("FileStream.Read: This stream is not readable.")
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
291 Throw New OutOfMemoryException("FileStream.Read: Failed to create an event object.")
292 End If
293 Try
294 ret = ReadFile(This.handle, VarPtr(buffer[offset]), count, 0, overlapped)
295 If ret = FALSE Then
296 Dim error = GetLastError()
297 If error <> ERROR_IO_PENDING Then
298 Detail.ThrowWinIOException("FileStream.Read: Failed to read.", error)
299 End If
300 End If
301 ret = GetOverlappedResult(This.handle, overlapped, readBytes, TRUE)
302 If ret = FALSE Then
303 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
304 End If
305 offset += Read
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
312 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
313 End If
314 End If
315 Read = readBytes As Long
316 End Function
317
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()
329 If This.CanSeek() Then
330 If This.IsAsync() Then
331 Select Case origin
332 Case SeekOrigin.Begin
333 This.offset = offset
334 Case SeekOrigin.Current
335 This.offset += offset
336 Case SeekOrigin.End
337 This.offset = This.Length + offset
338 End Select
339 Seek = This.offset As Int64
340 If Seek < 0 Then
341' Throw ArgumentException("FileStream.Seek: Cannot seek to negative offset.")
342 End If
343 Else
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
356 End If
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)
365 disposedCheck()
366 If This.CanWrite() and This.CanSeek() Then
367 If This.IsAsync() Then
368 Else
369 Dim current = This.Position()
370 This.Position(value)
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
376 End If
377 End If
378 End Sub
379
380/* Synchronized*/
381
382 Override Function ToString() As String
383 Return This.Name()
384 End Function
385
386 Sub Unlock(position As Int64, length As Int64)
387 disposedCheck()
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
393 Dim ret = UnlockFile(handle, LODWORD(position As QWord), HIDWORD(position As QWord),
394 LODWORD(length As QWord), HIDWORD(length As QWord))
395 If ret = FALSE Then
396 Detail.ThrowWinLastErrorIOException("FileStream.Read: Failed to read.")
397 End If
398 End Sub
399
400 Override Sub Write(buffer As *Byte, offset As Long, count As Long)
401 disposedCheck()
402 If This.CanWrite() Then
403 Dim writeBytes As DWord
404 If This.IsAsync() Then
405 Dim overlapped As OVERLAPPED
406 SetQWord(VarPtr(overlapped.Offset), offset)
407 overlapped.hEvent = CreateEvent(0, TRUE, FALSE, 0)
408 Dim ret = WriteFile(This.handle, VarPtr(buffer[offset]), count, 0, overlapped)
409 If ret <> FALSE Or GetLastError() = ERROR_IO_PENDING Then
410 GetOverlappedResult(This.handle, overlapped, writeBytes, TRUE)
411 End If
412 offset += writeBytes
413 CloseHandle(overlapped.hEvent)
414 Else
415 WriteFile(This.handle, VarPtr(buffer[offset]), count, VarPtr(writeBytes), ByVal NULL)
416 End If
417 End If
418 End Sub
419
420Protected
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
428 Override Function CreateWaitHandle() As System.Threading.WaitHandle
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
434 End Function
435
436Private
437 Sub disposedCheck()
438 If handle = 0 Then
439' Throw ObjectDisposedException("FileStream: This stream has closed.")
440 End If
441 End Sub
442
443End Class
444
445
446End Namespace
447End Namespace
Note: See TracBrowser for help on using the repository browser.