io — 입력/출력 스트림

이 모듈은 추가적인 유형의 stream(파일 형태) 객체와 헬퍼 함수를 포함합니다. 표준 read/write/seek 스트림 인터페이스를 구현하는 인메모리 텍스트 및 바이너리 버퍼(StringIO, BytesIO)와 함께 open() 빌트인을 제공합니다.

개념적 계층 구조

CPython과의 차이점

스트림 기반 클래스의 개념적 계층 구조는 이 절에서 설명하는 것처럼 MicroPython에서 단순화되어 있습니다.

모든 구체 클래스의 동작을 위한 토대 역할을 하는 (추상) 기반 스트림 클래스는 CPython에서 몇 가지 이분법(쌍을 이루는 분류)을 따릅니다. MicroPython에서는 더 높은 효율성을 달성하고 자원을 절약하기 위해 이들을 다소 단순화하고 암묵적으로 만들었습니다.

CPython에서 중요한 이분법 중 하나는 버퍼링되지 않은 스트림과 버퍼링된 스트림입니다. MicroPython에서는 현재 모든 스트림이 버퍼링되지 않습니다. 이는 모든 최신 OS와 심지어 많은 RTOS 및 파일시스템 드라이버가 이미 자신의 측에서 버퍼링을 수행하기 때문입니다. 또 다른 버퍼링 계층을 추가하는 것은 역효과를 낳으며(“버퍼블로트”로 알려진 문제) 귀중한 메모리를 소모합니다. 버퍼링이 유용할 수 있는 경우도 여전히 존재하므로, 나중에 선택적 버퍼링 지원을 도입할 수도 있습니다.

그러나 CPython에서 또 다른 중요한 이분법은 “버퍼링 여부”와 결부되어 있습니다. 즉, 스트림이 짧은 읽기/쓰기를 발생시킬 수 있는지 여부입니다. 짧은 읽기란 예를 들어 사용자가 스트림에서 10바이트를 요청했지만 그보다 적게 받는 경우이며, 쓰기도 마찬가지입니다. CPython에서 버퍼링되지 않은 스트림은 자동으로 짧은 연산에 취약한 반면, 버퍼링된 스트림은 그에 대해 보장됩니다. 짧은 읽기/쓰기가 없다는 것은 중요한 특성으로, 더 간결하고 효율적인 프로그램을 개발할 수 있게 해 줍니다. 이는 MicroPython에서 매우 바람직한 점입니다. 따라서 MicroPython은 버퍼링된 스트림을 지원하지 않지만, 짧은 연산이 없는 스트림은 여전히 제공합니다. 짧은 연산이 발생할지 여부는 각 개별 클래스의 필요에 따라 다르지만, 위에 언급된 이유로 개발자는 짧은 연산이 없는 동작을 선호할 것을 강력히 권장합니다. 예를 들어, MicroPython 소켓은 짧은 읽기/쓰기를 피하도록 보장됩니다. 실제로 현재 코어에는 짧은 연산 스트림 클래스의 예가 없으며, 그러한 클래스는 특정 하드웨어에 특화될 것입니다.

짧은 연산이 없는 동작은 논블로킹 스트림의 경우 까다로워지는데, 블로킹 대 논블로킹 동작은 MicroPython이 완전히 지원하는 또 다른 CPython의 이분법입니다. 논블로킹 스트림은 데이터가 도착하거나 쓰여지기를 절대 기다리지 않습니다. 가능한 만큼 읽기/쓰기를 하거나, 데이터(또는 데이터를 쓸 수 있는 능력)의 부재를 신호로 알립니다. 분명히 이것은 “짧은 연산 없음” 정책과 충돌하며, 실제로 논블로킹 버퍼링된(따라서 짧은 연산 없는) 스트림의 경우는 CPython에서 복잡합니다. 어떤 곳에서는 그러한 조합이 금지되어 있고, 어떤 곳에서는 정의되지 않았거나 그저 문서화되지 않았으며, 어떤 경우에는 장황한 예외를 발생시킵니다. MicroPython에서는 문제가 훨씬 간단합니다. 논블로킹 스트림은 효율적인 비동기 연산에 중요하므로, 이 특성이 “짧은 연산 없음” 특성보다 우선합니다. 따라서 블로킹 스트림은 가능할 때마다 짧은 읽기/쓰기를 피하지만(짧은 읽기를 얻는 유일한 경우는 파일 끝에 도달하거나 오류가 발생한 경우이며, 다만 오류는 짧은 데이터를 반환하지 않고 예외를 발생시킵니다), 논블로킹 스트림은 연산이 블로킹되는 것을 피하기 위해 짧은 데이터를 생성할 수 있습니다.

마지막 이분법은 바이너리 스트림과 텍스트 스트림입니다. MicroPython은 물론 이들을 지원하지만, CPython에서 텍스트 스트림이 본질적으로 버퍼링되는 것과 달리 MicroPython에서는 그렇지 않습니다. (실제로 이것이 우리가 버퍼링 지원을 도입할 수 있는 경우 중 하나입니다.)

효율성을 위해 MicroPython은 위 계층 구조에 해당하는 추상 기반 클래스를 제공하지 않으며, 순수 Python으로 스트림 클래스를 구현하거나 서브클래싱하는 것은 불가능하다는 점에 유의하십시오.

함수

io.open(name: str, mode: str = 'r', **kwargs) Any

파일을 엽니다. 내장 open() 함수는 이 함수의 별칭입니다. mode 매개변수는 항상 지원되며, 다른 인자에 대한 지원은 다를 수 있습니다.

클래스

class io.IOBase

스트림(“파일 형태”) 객체를 위한 기반 클래스입니다. 구체 서브클래스는 아래의 저수준 I/O 메서드(readinto, write, ioctl)를 구현하며, 런타임이 그 위에 고수준 스트림 프로토콜(read, readline, readlines, close, 반복)을 구축하므로, 서브클래스가 해당 메서드를 정의하지 않더라도 모든 스트림 인스턴스가 이를 지원합니다.

구현 메서드(서브클래스에서 이들을 재정의하십시오):

readinto(buf: bytearray) int | None

쓰기 가능한 버퍼 buf로 바이트를 읽어 들입니다. 읽은 바이트 수, 스트림 끝에서 0, 또는 (논블로킹 스트림의 경우) 현재 사용할 수 있는 데이터가 없으면 None을 반환합니다.

write(buf: bytes) int | None

buf의 바이트를 씁니다. 쓴 바이트 수, 또는 (논블로킹 스트림의 경우) 지금 쓰기를 수행할 수 없으면 None을 반환합니다.

ioctl(request: int, arg: int) int

기반 스트림/장치를 제어합니다. requestMP_STREAM_* 요청 코드 중 하나입니다. 성공 시 음이 아닌 값을, 오류 시 음수 errno 값을 반환합니다.

스트림 프로토콜 메서드(모든 스트림 인스턴스에서 사용 가능):

read(size: int = -1)

최대 size 바이트(또는 텍스트 모드에서는 문자)를 읽어 반환합니다. size가 생략되거나 음수이면 스트림 끝까지 읽습니다. 바이너리 스트림의 경우 bytes를, 텍스트 스트림의 경우 str을 반환하며, 빈 결과는 스트림 끝을 나타냅니다.

readline(size: int = -1)

한 줄을 읽어 반환하며, 존재하는 경우 끝의 줄바꿈 문자를 포함합니다. size가 주어지면 최대 size 바이트(또는 문자)를 읽습니다. 스트림 끝에서는 빈 bytes / str을 반환합니다.

readlines() list

스트림 끝까지 읽어 각각 끝의 줄바꿈을 포함하는 줄들의 list를 반환합니다.

close() None

스트림을 닫고 그 기반이 되는 모든 리소스를 해제합니다. 닫힌 스트림에 대한 연산은 OSError(인메모리 스트림의 경우 ValueError)를 발생시킵니다.

seek(offset: int, whence: int = 0) int

현재 스트림 위치를 whence를 기준으로 offset 바이트만큼 변경합니다(0 = 스트림 시작, 1 = 현재 위치, 2 = 스트림 끝). 새 절대 위치를 반환합니다. 탐색할 수 없는 스트림에서는 OSError를 발생시킵니다.

tell() int

스트림에서 현재 절대 위치를 반환합니다. seek(0, 1)과 동일합니다.

flush() None

모든 쓰기 버퍼를 플러시하여 대기 중인 데이터를 기반 장치나 파일로 밀어냅니다. 버퍼링하지 않는 스트림에서는 아무 동작도 하지 않습니다.

스트림을 직접 반복하면 반복마다 한 줄씩 생성됩니다. 이는 빈 줄로 표시되는 스트림 끝 센티넬이 반환될 때까지 루프에서 readline()을 호출하는 것과 동일합니다. 스트림은 또한 컨텍스트 관리자 프로토콜을 지원하므로, with open(...) as f:는 스트림을 자동으로 닫습니다.

참고

MicroPython의 스트림 모듈은 또한 “1”이 접미된 C 헬퍼인 mp_stream_read1_obj, mp_stream_readinto1_obj, mp_stream_write1_obj를 노출하는데, 이들은 요청이 완전히 충족될 때까지 반복하는 대신 단일 기반 I/O 호출을 수행합니다. 이들은 machine.UART 같은 클래스가 자체 read / write를 구현하기 위해 내부적으로 사용하지만, 어떤 표준 스트림 클래스도 이들을 Python에서 호출 가능한 read1 / readinto1 / write1 메서드로 바인딩하지 않습니다.

class io.StringIO(string: str = '')

텍스트 모드 입력/출력을 위한 인메모리 파일 형태 객체입니다(“t” 한정자로 연 일반 파일과 유사). 초기 내용은 string 매개변수로 지정할 수 있습니다(일반 문자열이어야 합니다). 인스턴스는 또한 컨텍스트 관리자 프로토콜을 지원합니다(with 문에서 사용 가능).

read(size: int = -1) str

최대 size 문자를 읽어 반환합니다. size가 생략되거나 음수이면 남은 모든 내용을 읽어 반환합니다.

readline(size: int = -1) str

한 줄을 읽어 반환합니다. size가 주어지면 최대 size 문자를 읽습니다.

readinto(buf: bytearray) int

미리 할당된 쓰기 가능한 버퍼 buf로 읽어 들이고 읽은 바이트 수를 반환합니다.

write(s: str) int

문자열 s를 쓰고 쓴 문자 수를 반환합니다.

seek(offset: int, whence: int = 0) int

스트림 위치를 whence를 기준으로 offset만큼 변경하고(0 = 시작, 1 = 현재, 2 = 끝) 새 절대 위치를 반환합니다.

tell() int

현재 스트림 위치를 반환합니다.

flush() None

쓰기 버퍼를 플러시합니다. 인메모리 스트림에서는 아무 동작도 하지 않습니다.

close() None

스트림을 닫고 기반 버퍼를 해제합니다. 닫힌 스트림에 대한 이후 연산은 ValueError를 발생시킵니다.

getvalue() str

기반 버퍼의 현재 내용을 반환합니다.

class io.StringIO(alloc_size: int)

최대 alloc_size 바이트를 담도록 미리 할당된 빈 StringIO 객체를 생성하여, 그만큼의 바이트를 쓰는 동안 버퍼가 재할당되지 않도록 합니다(메모리 부족 상황이나 메모리 단편화를 방지). 이 생성자는 MicroPython 확장이며, 일반 사용자 애플리케이션이 아니라 특수한 경우나 시스템 수준 라이브러리에만 권장됩니다.

CPython과의 차이점

이 생성자는 MicroPython 확장입니다.

read(size: int = -1) str

최대 size 문자를 읽어 반환합니다. size가 생략되거나 음수이면 남은 모든 내용을 읽어 반환합니다.

readline(size: int = -1) str

한 줄을 읽어 반환합니다. size가 주어지면 최대 size 문자를 읽습니다.

readinto(buf: bytearray) int

미리 할당된 쓰기 가능한 버퍼 buf로 읽어 들이고 읽은 바이트 수를 반환합니다.

write(s: str) int

문자열 s를 쓰고 쓴 문자 수를 반환합니다.

seek(offset: int, whence: int = 0) int

스트림 위치를 whence를 기준으로 offset만큼 변경하고(0 = 시작, 1 = 현재, 2 = 끝) 새 절대 위치를 반환합니다.

tell() int

현재 스트림 위치를 반환합니다.

flush() None

쓰기 버퍼를 플러시합니다. 인메모리 스트림에서는 아무 동작도 하지 않습니다.

close() None

스트림을 닫고 기반 버퍼를 해제합니다. 닫힌 스트림에 대한 이후 연산은 ValueError를 발생시킵니다.

getvalue() str

기반 버퍼의 현재 내용을 반환합니다.

class io.BytesIO(string: bytes = b'')

바이너리 모드 입력/출력을 위한 인메모리 파일 형태 객체입니다(“b” 한정자로 연 일반 파일과 유사). 초기 내용은 string 매개변수로 지정할 수 있습니다(바이트 객체여야 합니다). 인스턴스는 또한 컨텍스트 관리자 프로토콜을 지원합니다(with 문에서 사용 가능).

read(size: int = -1) bytes

최대 size 바이트를 읽어 반환합니다. size가 생략되거나 음수이면 남은 모든 내용을 읽어 반환합니다.

readline(size: int = -1) bytes

한 줄을 읽어 반환합니다. size가 주어지면 최대 size 바이트를 읽습니다.

readinto(buf: bytearray) int

미리 할당된 쓰기 가능한 버퍼 buf로 읽어 들이고 읽은 바이트 수를 반환합니다.

write(b: bytes) int

바이트 형태 객체 b를 쓰고 쓴 바이트 수를 반환합니다.

seek(offset: int, whence: int = 0) int

스트림 위치를 whence를 기준으로 offset만큼 변경하고(0 = 시작, 1 = 현재, 2 = 끝) 새 절대 위치를 반환합니다.

tell() int

현재 스트림 위치를 반환합니다.

flush() None

쓰기 버퍼를 플러시합니다. 인메모리 스트림에서는 아무 동작도 하지 않습니다.

close() None

스트림을 닫고 기반 버퍼를 해제합니다. 닫힌 스트림에 대한 이후 연산은 ValueError를 발생시킵니다.

getvalue() bytes

기반 버퍼의 현재 내용을 반환합니다.

class io.BytesIO(alloc_size: int)

최대 alloc_size 바이트를 담도록 미리 할당된 빈 BytesIO 객체를 생성하여, 그만큼의 바이트를 쓰는 동안 버퍼가 재할당되지 않도록 합니다(메모리 부족 상황이나 메모리 단편화를 방지). 이 생성자는 MicroPython 확장이며, 일반 사용자 애플리케이션이 아니라 특수한 경우나 시스템 수준 라이브러리에만 권장됩니다.

CPython과의 차이점

이 생성자는 MicroPython 확장입니다.

read(size: int = -1) bytes

최대 size 바이트를 읽어 반환합니다. size가 생략되거나 음수이면 남은 모든 내용을 읽어 반환합니다.

readline(size: int = -1) bytes

한 줄을 읽어 반환합니다. size가 주어지면 최대 size 바이트를 읽습니다.

readinto(buf: bytearray) int

미리 할당된 쓰기 가능한 버퍼 buf로 읽어 들이고 읽은 바이트 수를 반환합니다.

write(b: bytes) int

바이트 형태 객체 b를 쓰고 쓴 바이트 수를 반환합니다.

seek(offset: int, whence: int = 0) int

스트림 위치를 whence를 기준으로 offset만큼 변경하고(0 = 시작, 1 = 현재, 2 = 끝) 새 절대 위치를 반환합니다.

tell() int

현재 스트림 위치를 반환합니다.

flush() None

쓰기 버퍼를 플러시합니다. 인메모리 스트림에서는 아무 동작도 하지 않습니다.

close() None

스트림을 닫고 기반 버퍼를 해제합니다. 닫힌 스트림에 대한 이후 연산은 ValueError를 발생시킵니다.

getvalue() bytes

기반 버퍼의 현재 내용을 반환합니다.