Stream 클래스
namespace System.IO
{
public abstract class Stream : MarshalByRefObject, IDisposable
{
protected Stream();
// 읽기
public abstract bool CanRead { get; }
public abstract int Read(byte[] buffer, int offset, int count);
public virtual int ReadByte();
public Task<int> ReadAsync(byte[] buffer, int offset, int count);
public virtual Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
public virtual int EndRead(IAsyncResult asyncResult);
// 쓰기
public abstract bool CanWrite { get; }
public abstract void Write(byte[] buffer, int offset, int count);
public virtual void WriteByte(byte value);
public Task WriteAsync(byte[] buffer, int offset, int count);
public virtual Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
public virtual IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state);
public virtual void EndWrite(IAsyncResult asyncResult);
// 탐색
public abstract bool CanSeek { get; }
public abstract long Position { get; set; }
public abstract long Length { get; }
public abstract void SetLength(long value);
public abstract long Seek(long offset, SeekOrigin origin);
// 복사
public void CopyTo(Stream destination);
public void CopyTo(Stream destination, int bufferSize);
public Task CopyToAsync(Stream destination);
public Task CopyToAsync(Stream destination, int bufferSize);
public virtual Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken);
// 배출, 닫기
public abstract void Flush();
public Task FlushAsync();
public virtual Task FlushAsync(CancellationToken cancellationToken);
public virtual void Close();
public void Dispose();
protected virtual void Dispose(bool disposing);
// 시간 만료
public virtual bool CanTimeout { get; }
public virtual int ReadTimeout { get; set; }
public virtual int WriteTimeout { get; set; }
// 기타
public static readonly Stream Null;
public static Stream Synchronized(Stream stream);
// 미사용
protected virtual WaitHandle CreateWaitHandle();
protected virtual void ObjectInvariant();
}
}
- 추상 클래스, 모든 스트림 클래스의 기반
- 읽기, 쓰기, 탐색 기능을 지원
using System;
using System.IO;
namespace Test
{
class Program
{
static void Main(string[] args)
{
using (Stream s = new FileStream("test.txt", FileMode.Create))
{
Console.WriteLine($"읽기 가능: {s.CanRead}");
Console.WriteLine($"쓰기 가능: {s.CanWrite}");
Console.WriteLine($"탐색 가능: {s.CanSeek}");
Console.WriteLine();
// 바이트 단위로 2번 쓰고, 바이트 배열을 기록
s.WriteByte(101);
s.WriteByte(102);
byte[] block = {1, 2, 3, 4, 5};
s.Write(block, 0, block.Length);
Console.WriteLine($"스트림 길이: {s.Length}");
Console.WriteLine($"스트림 포인터 위치: {s.Position}");
Console.WriteLine();
// 스트림 포인터를 맨 처음(0)으로 이동
s.Position = 0;
// 읽어오기
Console.WriteLine($"ReadByte = {s.ReadByte()}");
Console.WriteLine($"ReadByte = {s.ReadByte()}");
// 10 바이트를 불러오라고 해도 스트림에 남은 바이트만큼 읽어온다
byte[] newBlock = new byte[10];
int readByte = s.Read(newBlock, 0, 10);
Console.WriteLine($"읽어온 바이트 수 = {readByte}");
for (int i = 0; i < readByte; i++)
{
Console.Write($"{newBlock[i]} ");
}
Console.WriteLine();
Console.WriteLine();
// 이미 끝에 있는 상태의 스트림에 읽기를 시도하면...
Console.WriteLine($"ReadByte = {s.ReadByte()}");
Console.WriteLine($"10 바이트 읽기: 읽어온 바이트 수 = {s.Read(newBlock, 0, 10)}");
Console.WriteLine();
}
}
}
}
읽기
- CanRead로 읽기 가능한지 확인 가능
- Read는 읽은 만큼의 바이트 수를 반환
* 버퍼 배열, 버퍼 배열에서 기록을 시작할 위치, 스트림에서 읽어올 바이트 수
* 읽으려는 수보다 적게 읽혔다면 스트림의 끝이거나, 스트림이 읽으려는 수 보다 적은 단위로 자료 제공
네트워크 스트림에서 이런 경우가 많기 때문에 반복해서 읽어줘야 한다
* 읽지 못한 부분의 바이트들은 이전 값을 유지 - 0 따위로 덮어 씌워지지 않음
- ReadByte는 바이트 한개를 읽어옴
* 읽은 바이트 값을 리턴
* 스트림의 끝이라면 -1을 리턴
쓰기
- CanWrite로 쓰기 가능한지 확인 가능
- Write, WriteByte는 읽기 계열과 비슷, 쓰기 불가능한 경우라면 예외 발생
탐색
- CanSeek로 탐색 가능한지 확인 가능
- Length로 길이 조회, SetLength로 길이 변경
- 위치 조회 및 변경
* Position: 스트림의 시작 지점에 상대적
* Seek: 스트림의 시작 / 끝 / 현재 지점에 상대적 (System.IO.SeekOrigin을 사용)
- 탐색 불가 스트림은?
* 스트림을 끝까지 읽는 것으로 길이를 알 수 있음
* 뒤로 돌아가고 싶다면 다시 읽을 수 밖에 없음
배출
- Flush, 버퍼에 저장된 데이터를 실제 스트림이 가야 할 곳으로 갱신시켜줌
닫기
- 반드시 처분해줘야 함, 귀찮다면 using 블록 사용
- Dispose, Close가 동일한 기능 수행
- 닫는 순간 Flush는 자동 수행
시간 만료
- CanTimeout이 true라면 시간 만료 기능 사용 가능
- ReadTimeout, WriteTimeout 속성에 ms 단위 시간을 지정하여 타임아웃 시간 설정
* 0이면 타임 아웃 없음
* 시간 초과시 예외를 던짐
스레드 안정성
- 기본적으로 스레드에 안전하지 않음
- Synchronized를 호출하여 받은 레퍼는 독점 락이 걸려있으므로 이 쪽을 사용
'C#' 카테고리의 다른 글
[C#] NamedPipeServerStream, NamedPipeClientStream (0) | 2023.12.04 |
---|---|
[C#] PipeStream (0) | 2023.12.01 |
[C#] MemoryStream (0) | 2023.11.24 |
[C#] FileStream (0) | 2023.11.20 |
[C#] Task (0) | 2023.11.06 |
[C#] Thread (0) | 2023.11.01 |
[C#] Stopwatch (0) | 2023.10.30 |
[C#] PerformanceCounter, PerformanceCounterCategory (0) | 2023.10.28 |