[605] | 1 | 'Classes/System/IO/FileStream.ab
|
---|
| 2 |
|
---|
[271] | 3 | Namespace System
|
---|
| 4 | Namespace 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] | 18 | Class FileStream
|
---|
[256] | 19 | Inherits Stream
|
---|
[605] | 20 | Protected
|
---|
| 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] | 123 | Public
|
---|
[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] | 221 | Public
|
---|
[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] | 268 | Public
|
---|
[256] | 269 | /* Safe~Handle系の実装は要相談!! */
|
---|
| 270 | /* Function SafeFileHandle() As SafeFileHandle
|
---|
| 271 | End Function*/
|
---|
| 272 |
|
---|
| 273 | Public
|
---|
[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 |
|
---|
| 375 | Protected
|
---|
[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] | 388 | Private
|
---|
| 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] | 395 | End Class
|
---|
[271] | 396 |
|
---|
| 397 | End Namespace
|
---|
| 398 | End Namespace
|
---|