1. 데이터 스트림

프로그램이 그 자체로 섬으로 존재하는 경우는 드뭅니다. 프로그램은 일반적으로 어떻게든 "외부 세계"와 상호 작용합니다. 이는 키보드에서 데이터 읽기, 메시지 보내기, 인터넷에서 페이지 다운로드 또는 반대로 원격 서버에 파일 업로드를 통해 발생할 수 있습니다.

프로그램과 외부 세계 간의 데이터 교환 이라는 한 단어로 이러한 모든 동작을 언급할 수 있습니다 . 잠깐, 한 단어가 아닙니다.

물론 데이터 교환 자체는 데이터 수신과 데이터 전송의 두 부분으로 나눌 수 있습니다. 예를 들어, 개체를 사용하여 키보드에서 데이터를 읽습니다 Scanner. 이것은 데이터를 받는 것입니다. 그리고 명령을 사용하여 화면에 데이터를 표시합니다 System.out.println(). 이것이 데이터 전송입니다.

프로그래밍에서 "스트림"이라는 용어는 데이터 교환을 설명하는 데 사용됩니다. 그 용어는 어디에서 왔습니까?

실생활에서는 물의 흐름이나 의식의 흐름을 가질 수 있습니다. 프로그래밍에는 데이터 스트림이 있습니다 .

스트림은 다목적 도구입니다. 이를 통해 프로그램은 어디에서나 데이터를 수신하고(입력 스트림) 어디에서나 데이터를 보낼 수 있습니다(출력 스트림). 따라서 두 가지 유형이 있습니다.

  • 입력 스트림은 데이터를 수신하기 위한 것입니다.
  • 출력 스트림은 데이터를 전송하기 위한 것입니다.

스트림을 '유형'으로 만들기 위해 Java 작성자는 InputStream및 이라는 두 가지 클래스를 작성했습니다 OutputStream.

클래스 에는 데이터를 읽을 수 있는 메서드가 InputStream있습니다 . read()그리고 클래스 에는 데이터를 쓸 수 있는 메서드가 OutputStream있습니다 . write()다른 방법도 있지만 나중에 자세히 설명합니다.

바이트 스트림

우리는 어떤 종류의 데이터에 대해 이야기하고 있습니까? 어떤 형식을 취합니까? 즉, 이러한 클래스는 어떤 데이터 유형을 지원합니까?

이들은 일반 클래스이므로 가장 일반적인 데이터 유형인 byte. An은 OutputStream바이트(및 바이트 배열)를 쓸 수 있고 InputStream객체는 바이트(또는 바이트 배열)를 읽을 수 있습니다. 그게 전부입니다. 다른 데이터 유형은 지원하지 않습니다.

따라서 이러한 스트림을 바이트 스트림 이라고도 합니다 .

스트림의 한 가지 기능은 해당 데이터를 순차적으로만 읽을(또는 쓸 수) 수 있다는 것입니다. 앞에 오는 모든 데이터를 읽지 않고는 스트림 중간에서 데이터를 읽을 수 없습니다.

이것이 클래스 전체에서 키보드에서 데이터를 읽는 방식입니다 Scanner. 키보드에서 한 줄씩 순차적으로 데이터를 읽습니다. 한 줄, 다음 줄, 다음 줄 등을 읽습니다. 적절하게도 행을 읽는 방법을 이라고 합니다 nextLine().

에 데이터 쓰기 OutputStream도 순차적으로 발생합니다. 이에 대한 좋은 예는 콘솔 출력입니다. 줄을 출력하고 다른 줄과 다른 줄을 출력합니다. 순차 출력입니다. 첫 번째 줄, 열 번째 줄, 두 번째 줄을 출력할 수 없습니다. 모든 데이터는 출력 스트림에 순차적으로만 기록됩니다.

문자 스트림

최근에 문자열이 두 번째로 많이 사용되는 데이터 유형이라는 사실을 알게 되었으며 실제로 그렇습니다. 많은 정보가 문자와 전체 문자열의 형태로 전달됩니다. 컴퓨터는 모든 것을 바이트로 보내고 받는 데 탁월하지만 인간은 완벽하지 않습니다.

이 사실을 고려하여 Java 프로그래머는 두 개의 클래스를 더 작성 Reader했습니다 Writer. 클래스 Reader는 클래스와 유사 InputStream하지만 read()메소드는 바이트가 아니라 문자( char)를 읽습니다. 클래스 는 클래스 Writer에 해당합니다 OutputStream. 그리고 클래스와 마찬가지로 바이트가 아닌 Reader문자( )로 작동합니다 .char

이 네 가지 클래스를 비교하면 다음 그림을 얻을 수 있습니다.

바이트(바이트) 문자(char)
데이터 읽기
InputStream
Reader
데이터 쓰기
OutputStream
Writer

실용적인 응용 프로그램

, 및 클래스 자체는 데이터 InputStream를 읽을 수 있는(또는 데이터 를 쓸 수 있는) 구체적인 개체와 연결되어 있지 않기 때문에 누구도 직접 사용하지 않습니다. 하지만 이 네 가지 클래스에는 많은 작업을 수행할 수 있는 많은 자손 클래스가 있습니다.OutputStreamReaderWriter


2. InputStream클래스

InputStream클래스는 수백 개의 하위 클래스에 대한 상위 클래스이기 때문에 흥미롭습니다. 자체 데이터는 없지만 모든 파생 클래스가 상속하는 메서드가 있습니다.

일반적으로 스트림 개체가 내부적으로 데이터를 저장하는 경우는 드뭅니다. 스트림은 데이터를 읽고 쓰기 위한 도구이지만 스토리지는 아닙니다. 즉, 예외가 있습니다.

InputStream클래스 및 모든 하위 클래스 의 메서드 :

행동 양식 설명
int read()
스트림에서 1바이트를 읽습니다.
int read(byte[] buffer)
스트림에서 바이트 배열을 읽습니다.
byte[] readAllBytes()
스트림에서 모든 바이트를 읽습니다.
long skip(long n)
스트림에서 바이트를 건너뜁니다 n(읽고 버립니다).
int available()
스트림에 남아 있는 바이트 수를 확인합니다.
void close()
스트림을 닫습니다

다음 방법을 간단히 살펴보겠습니다.

read()방법

이 메서드는 스트림에서 1바이트를read() 읽고 반환합니다. 반환 유형이 혼동될 수 있습니다 . 이 유형은 표준 정수 유형이기 때문에 선택되었습니다 . 의 처음 3바이트는 0입니다.intintint

read(byte[] buffer)방법

이것은 방법의 두 번째 변형입니다 read(). InputStream한 번에 모두 에서 바이트 배열을 읽을 수 있습니다 . 바이트를 저장할 배열을 인수로 전달해야 합니다. 이 메서드는 실제로 읽은 바이트 수인 숫자를 반환합니다.

10킬로바이트 버퍼가 있고 클래스를 사용하여 파일에서 데이터를 읽는다고 가정해 보겠습니다 FileInputStream. 파일에 2킬로바이트만 포함된 경우 모든 데이터가 버퍼 배열로 로드되고 메서드는 숫자 2048(2킬로바이트)을 반환합니다.

readAllBytes()방법

아주 좋은 방법입니다. 그것은 다 떨어질 때까지 모든 데이터를 읽고 InputStream단일 바이트 배열로 반환합니다. 이것은 작은 파일을 읽을 때 매우 편리합니다. 큰 파일은 물리적으로 메모리에 맞지 않을 수 있으며 메서드는 예외를 throw합니다.

skip(long n)방법

이 방법을 사용하면 개체에서 처음 n바이트를 건너뛸 수 있습니다 InputStream. 데이터를 엄격하게 순차적으로 읽기 때문에 이 메서드는 스트림에서 처음 n바이트를 읽고 버립니다.

실제로 건너뛴 바이트 수를 반환합니다(바이트를 건너뛰기 전에 스트림이 종료된 경우 n).

int available()방법

이 메서드는 스트림에 아직 남아 있는 바이트 수를 반환합니다.

void close()방법

메서드 close()는 데이터 스트림을 닫고 연결된 외부 리소스를 해제합니다. 스트림이 닫히면 더 이상 데이터를 읽을 수 없습니다.

매우 큰 파일을 복사하는 예제 프로그램을 작성해 봅시다. readAllBytes()전체 파일을 메모리로 읽는 방법을 사용할 수 없습니다 . 예:

암호 메모
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);
FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = new byte[65536]; // 64Kb
   while (input.available() > 0)
   {
      int real = input.read(buffer);
      output.write(buffer, 0, real);
   }
}



InputStream파일에서 읽기
OutputStream위해 파일에 쓰기 위해

데이터를 읽을 버퍼
스트림에 데이터가 있는 한

버퍼로 데이터 읽기 버퍼
에서 두 번째 스트림으로 데이터 쓰기

이 예제에서는 두 개의 클래스를 사용했습니다. 는 파일에서 데이터를 읽는 데 사용 FileInputStream되는 자손 이고, 는 파일에 데이터를 쓰는 데 사용되는 자손입니다 . 조금 후에 두 번째 수업에 대해 이야기하겠습니다.InputStreamFileOutputStreamOutputStream

여기서 또 다른 흥미로운 점은 real변수입니다. 파일에서 마지막 데이터 블록을 읽을 때 데이터가 64KB 미만일 수 있습니다. 따라서 전체 버퍼가 아니라 그 일부인 첫 번째 real바이트만 출력해야 합니다. 이것이 바로 write()방법에서 일어나는 일입니다.



3. Reader클래스

클래스 는 클래스 Reader의 완전한 아날로그입니다 InputStream. 유일한 차이점은 char바이트가 아닌 문자( )로 작동한다는 것입니다. InputStream클래스 와 마찬가지로 Reader클래스는 그 자체로 어디에도 사용되지 않습니다. 수백 개의 하위 클래스에 대한 상위 클래스이며 이들 모두에 대한 공통 메서드를 정의합니다.

클래스 의 메서드 Reader(및 모든 하위 클래스):

행동 양식 설명
int read()
char스트림에서 하나를 읽습니다.
int read(char[] buffer)
char스트림에서 배열을 읽습니다.
long skip(long n)
스트림을 건너뜁니다 n chars(읽고 버립니다).
boolean ready()
스트림에 아직 남아있는 것이 있는지 확인합니다.
void close()
스트림을 닫습니다

방법은 InputStream약간의 차이가 있지만 클래스의 방법과 매우 유사합니다.

int read()방법

이 메서드는 char스트림에서 하나를 읽고 반환합니다. 유형 char은 로 확장되지만 int결과의 처음 두 바이트는 항상 0입니다.

int read(char[] buffer)방법

이것은 방법의 두 번째 변형입니다 read(). Reader한 번에 모두 에서 char 배열을 읽을 수 있습니다 . 문자를 저장할 배열을 인수로 전달해야 합니다. 이 메서드는 실제로 읽은 문자 수인 숫자를 반환합니다.

skip(long n)방법

이 방법을 사용하면 개체에서 처음 n자를 건너뛸 수 있습니다 Reader. 클래스 의 유사한 메서드와 정확히 동일하게 작동합니다 InputStream. 실제로 건너뛴 문자 수를 반환합니다.

boolean ready()방법

true스트림에 읽지 않은 바이트가 있으면 반환합니다 .

void close()방법

메서드 close()는 데이터 스트림을 닫고 연결된 외부 리소스를 해제합니다. 스트림이 닫히면 더 이상 데이터를 읽을 수 없습니다.

비교를 위해 텍스트 파일을 복사하는 프로그램을 작성해 보겠습니다.

암호 메모
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileReader reader = new FileReader(src);
FileWriter writer = new FileWriter(dest))
{
   char[] buffer = new char[65536]; // 128Kb
   while (reader.ready())
   {
      int real = reader.read(buffer);
      writer.write(buffer, 0, real);
   }
}



Reader파일에서 읽기
Writer위해 파일에 쓰기 위해

데이터를 읽을 버퍼
스트림에 데이터가 있는 한

버퍼로 데이터
읽기 버퍼에서 두 번째 스트림으로 데이터 쓰기