본문 바로가기
C#

[C#] Stream

by DANEW 2023. 11. 17.

Stream 클래스

 

 

Stream 클래스 (System.IO)

바이트 시퀀스에 대한 일반 뷰를 제공합니다. 이 클래스는 추상 클래스입니다.

learn.microsoft.com

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