JongDDA의 한걸음 한걸음씩
[Java] 입출력(I/O) 본문
입출력(I/O)
I/O 란 Input 과 Output의 약자로 입출력이라고 한다. 입출력은 컴퓨터 내부 또는 외부의 장치와 프로그램간의 데이터를 주고받는 것을 말한다.
스트림(stream)
자바에서 입출력을 수행하려면, 즉 어느 한쪽에서 다른 쪽으로 데이터를 전달하려면 두 대상을 연결하고 데이터를 전송할 수 있는 무언가가 필요한데 이것을 스트림(stream)이라고 정의한다. 스트림은 연속적인 데이터의 흐름을 물에 비유하여 붙여진 이름인데. 물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다.
그래서 입력과 출력을 동시에 출력하려면 입력을 위한 입력스트림(Input stream)과 출력을 위한 출력스트림(Output stream), 모두 2개가 필요하다.
바이트 기반 스트림 - InputStream, OutputStream
스트림은 바이트단위로 데이터를 전송하며 입출력 대상에 따라 다음과 같은 입출력스트림이 있다.
입력스트림 | 출력스트림 | 입출력 대상의 종류 |
FileInputStream | FileOutputStream | 파일 |
ByteArrayInputStream | ByteArrayOutputStream | 메모리(byte배열) |
PipedInputStream | PipedOutputStream | 프로세스(프로세스간의 통신) |
AudioInputStream | AudioOutputStream | 오디오장치 |
위의 표와 같이 여러 종류의 입출력스트림이 있으며, 어떠한 대상에 대해서 작업을 할 것인지 그리고 입력을 할 것인지 출력을 할 것인지에 따라서 해당 스트림을 선택해서 사용하면 된다.
자바에서는 java.io 패키지를 통해 많은 종류의 입출력관련 클래스들을 제공하고 있으며, 입출력을 처리할 수 잇는 표준화된 방법을 제공함으로써 입출력의 대상이 달라져도 동일한 방법으로 입출력이 가능하기 때문에 프로그래밍 하기에 편하다.
보조 스트림
이전 언급한 스트림 외에도 스트림의 기능을 보완하지 위한 보조 스트림이 제공된다. 보조 스트림은 실제 데이터를 주고받는 스트림이 아니기 때문에 데이터를 입출력할 수 있는 기능은 없지만, 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있다.
예를들어 text.txt 라는 파일을 읽기 위해 FIleInputStream을 사용할 때, 성능 향상을 위해 버퍼를 이용하는 보조 스트림인 BufferedInputStream을 사용하는 코드는 다음과 같다.
// 우선적으로 기반 스트림 생성
FileInputStream fis = new FileInputStream("text.txt");
// 기반 스트림을 이용해서 보조 스트림을 생성한다.
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(); // 보조 스트림인 BufferedInputStream 으로부터 데이터를 읽는다.
보조스트림의 종류
입력 | 출력 | 설명 |
FilterInputStream | FilterOutputStream | 필터를 이용한 입출력 처리 |
BufferedInputStream | BufferedOutputStream | 버퍼를 이용한 입출력 성능향상 |
DataInputStream | DataOutputStream | int, float 와 같은 기본형 단위(primitive type)로 데이터를 처리 |
SequenceInputStream | 없음 | 두 개의 스트림을 하나로 연결 |
LineNumberInputStream | 없음 | 읽어 온 데이터의 라인 번호를 카운트 |
ObjectInputStream | ObjectOutputStream | 데이터를 객체단위로 읽고 쓰는데 사용 주로 파일을 이용하여 객체 직렬화와 관련있음 |
없음 | PrintStream | 버퍼를 이용하먀, 추가적인 print관련 기능 |
PushbackInputStream | 없음 | 버퍼를 이용해서 읽어 온 데이터를 다시 되돌리는 기능(unread) |
문자기반 스트림 - Reader, Writer
문자데이터를 입출력할 때는 바이트 기반 스트럼 대신 문자 기반 스트림을 사용해야 한다.
InputStream --> Reader
OutputStream --> Writer
바이트 기반 스트림 | 문자기반 스트림 |
FileInputStream FileOutputStream |
FileReader FileWriter |
ByteArrayInputStream ByteArrayOutputStream |
CharArrayReader CharArrayWriter |
PipedInputStream PipedOutputStream |
PipedReader PipedWriter |
StringBufferInputStream(deprecated) StringBufferOutputStream(deprecated) |
StringReader StringWriter |
InputStream, OutputStream
InputStream과 OutputStream은 모든 바이트 기반 스트림의 조상이며 다음과 같은 메서드가 선언되어 있다.
InputStream 메서드명 | 설명 |
int available() | 스트림으로부터 읽어 올 수 있는 데이터의 크기를 반환한다. |
void close() | 스트림을 닫음으로써 사용하고 있던 자원을 반환한다. |
void mark(int readlimit) | 현재위치를 표시해 놓는다. 후에 reset()에 의해서 표시해 놓은 위치로 다시 돌아갈 수 있다. readlimit은 되돌아갈 수 있는 byte 수이다. |
boolean markSupported() | mark()와 reset()을 지원하는지를 |
abstract int read() | 1 byte를 읽어 온다.(0~255사이의 값), 더 이상 읽어 올 데이터가 없으면 -1을 반환한다. abstract메서드라서 InputStream의 자손들은 자신의 상황에 알맞게 구현해야한다. |
int read(byte[] b) | 배열 b의 크기만큼 읽어서 배열을 채우고 읽어 온 데이터의 수를 반환한다. 반환하는 값은 항상 배열의 크기보다 작거나 같다. |
int read(byte[] b, int off, int len) | 최대 len개의 byte를 읽어서, 배열 b의 지정된 위치(off)부터 저장한다. 실제로 읽어 올 수 있는 데이터가 len개보다 적을 수 있다. |
void reset() | 스트림에서의 위치를 마지막으로 mark()이 호출되었던 위치로 되돌린다. |
long skip(long n) | 스트럼에서 주어진 길이(n)만큼을 건너뛴다 |
OutputStream | 설명 |
void close() | 입력소스를 닫음으로써 사용하고 있던 자원을 반환한다. |
void flush() | 스트림의 버퍼에 있는 모든 내용을 출력소스에 쓴다. |
abstract void write(int b) | 주어진 값을 출력소스에 쓴다. |
void write(byte[] b) | 주어진 배열 b에 저장된 모든 내용을 출력소스에 쓴다. |
void write(byte[] b, int off, int len) | 주어진 배열 b에 저장된 내용 중에서 off번째부터 len개 만큼만을 읽어서 출력소스에 쓴다. |
flush()는 버퍼가 있는 출력스트림의 경우에만 의미가 있으며, OutputStream에 정의된 flush()는 아무런 일도 하지 않는다. 스트림을 사용해서 모든 작업을 마치고 난 후에는 close()를 호출해서 반드시 닫아 주어야 한다. 그러나 ByteArrayInputStream과 같이 메모리를 사용하는 스트림과 System.in, System.out과 같은 표준 입출력 스트림을 닫아 주지 않아도 된다.
FileInputStream 과 FIleOutputStream
FileInputStream / FIleOutputStream 은 파일에 입출력을 하기 위한 스트림이다.
생성자 | 설명 |
FileInputStream(String name) | 지정된 파일이름(name)을 가진 실제 파일과 연결된 FileInputStream을 생성한다. |
FileInputStream(File file) | 파일의 이름이 String이 아닌 File 인스턴스로 지정해주어야 하는 점을 제외하고 FileInputStream(String name)와 같다. |
FileInputStream(FileDescriptor fdObj) | 파일 디스크립터(fdObj)로 FileInputStream을 생성한다. |
생성자 | 설명 |
FileOutputStream(String name) | 지정된 파일이름(name)을 가진 실제 파일과 연결된 FileOutputStream을 생성한다. |
FileOutputStream(String name, boolean append) | 지정된 파일이름(name)을 가진 실제 파일과 연결된 File OutputStream을 생성한다. 두번째 인자인 append를 true로 하면, 출력 시 기존의 파일내용의 마지막에 덧붙인다. false면, 기존의 파일내용을 덮어쓰게 된다. |
FileOutputStream(File file) | 파일의 이름을 String이 아닌 FIle 인스턴스로 지정해주어야하는 점을 제외하고 FileOutputStream(String name)과 같다. |
FileOutputStream(File file, boolean append) | 파일의 이름을 String이 아닌 FIle 인스턴스로 지정해주어야하는 점을 제외하고 FileOutputStream(String name, boolean append)와 같다. |
FileOutputStream(FileDescriptor fdObj) | 파일 디스크립터(fdObj)로 FileOutputStream을 생성한다. |
FilterInputStream 과 FilterOutputStream은 InputStream/OutputStream의 자손이면서 모든 보조 스트림의 조상이다.
보조스트림은 자체적으로 입출력을 수행할 수 없기 때문에 기반스트림을 필요로 한다.
protected FilterInputStream(InputStream in)
public FilterOutputStream(OutputStream out)
FilterInputStream/FilterOutputStream의 모든 메서드는 단순히 기반 스트림의 메서드를 그대로 호출할 뿐이다. FilterInputStream/FilterOutputStream자체로는 아무런 일도 하지 않음을 의미한다. FilterInputStream/FilterOutputStream 은 상속을 통해 원하는 작업을 수행하도록 읽고 쓰는 메서드를 오버라이딩 해야 한다.
public class FilterInputStream extends InputStream{
protected volatile InputStream in;
protected FilterInputStream(InputStream in){
this.in = in;
}
public int read() throws IOException {
return in.read();
}
...
}
생성자 FilterInputStream(InputStream in)는 접근 제어자가 protected이기 때문에 Filter InputStream의 인스턴스를 생성해서 사용할 수 없고 상속을 통해서 오버라이딩되어야 한다.
FilterInputStream/FilterOutputStream을 상속받아서 기반스트림에 보조기능을 추가한 보조스트림 클래스는 다음과 같다.
FilterInputStream의 자손 : BufferedInputStream, DataInputStream, PushbackInputStream 등
FilterOutputStream의 자손 : BufferedOutputStream, DataOutputStream, PushbackOutputStream 등
BufferedInputStream/BufferedOutputStream
BufferedInputStream/BufferedOutputStream은 스트림의 입출력 효율을 높이기 위해 버퍼를 사용하는 보조스트림이다. 한 바이트씩 입출력하는 것 보다는 버퍼를 이용해서 한 번에 여러 바이트를 입출력하는 것이 빠르기 때문에 대부분의 입출력 작업에 사용된다.
생성자 | 설명 |
BufferedInputStream(InputStream in, int size) | 주어진 InputStream인스턴스를 입력소스(input source)로하며지정된 크기(byte단위)의 버퍼를 갖는 BufferedInputStream 인스턴스를 생성한다. |
BufferedInputStream(InputStream in) | 주어진 InputStream인스턴스를 입력소스(input source)로하며 지정된 크기를 지정해주지 않으므로 기본적으로 8192 byte 크기의 버퍼를 갖게된다. |
메서드 / 생성자 | 설명 |
BufferedIOutputStream(OutputStream out, int size) | 주어진 OutputStream인스턴스를 출력소스(iOutput source)로하며지정된 크기(byte단위)의 버퍼를 갖는 BufferedOutputStream 인스턴스를 생성한다. |
BufferedOutputStream(OutputStream out) | 주어진 OutputStream인스턴스를 입력소스(output source)로하며 지정된 크기를 지정해주지 않으므로 기본적으로 8192 byte 크기의 버퍼를 갖게된다. |
flush() | 버퍼의 모든 내용을 출력소스에 출력한 다음, 버퍼를 비운다. |
close() | flush()를 호출해서 버퍼의 모든 내용을 출력소스에 출력하고, BufferedOutputStream인스턴스가 사용하던 모든 자원을 반환한다. |
SequenceInputSteam
SequenceInputSteam은 여러 개의 입력스트림을 연속적으로 연결해서 하나의 스트림으로 부터 데이터를 읽는 것과 같이 처리할 수 있도록 도와준다. SequenceInputSteam의 생성자를 제외하고 나머지 작업은 다른 입력스트림과 다르지 않다. 큰 파일을 여러 개의 작은 파일로 나누었다가 하나의 파일로 합치는 것과 같은 작업을 수행할 때 사용하면 좋을 것이다.
생성자 | 설명 |
SequenceInputSteam(Enumeration e) | Enumeration에 저장된 순서대로 입력스트림을 하나의 스트림으로 연결한다. |
SequenceInputSteam(InputStream s1, inputStream s2) | 두 개의 입력스트림 s1,s2를 하나로 연결한다. |
PrintStream
PrintStream은 데이터를 기반스트림에 다양한 형태로 출력할 수 있는 print, println, printf와 같은 메서드를 오버로딩하여 제공한다. PrintStream은 데이터를 적절한 문자로 출력하는 것이기 때문에 문자기반 스트림의 역할을 수행한다. JDK1.1에서 부터는 PrintStream보다 향상된 기능의 문자기반 스트림인 PrintWirter가 추가되었으나 그 동안 매우 빈번히 사용되된 System.out이 PrintStream이다 보니 둘 다 사용할 수밖에 없게 되었다.
PrintWriter가 PrintStream에 비해 다양한 언어의 문자를 처리하는데 적합하기 때문에 가능하면 PrintWriter를 사용하는 것이 좋다.
문자 기반 스트림 - Reader / Writer
바이트기반 스트림의 조상이 InputStream/OutputStream인 것과 같이 문자기반의 스트림에서는 Reader/Writer가 그와 같은 역할을 한다.
FIleReader/FIleWriter
파일로부터 텍스트 데이터를 읽고, 파일에 쓰는데 사용된다.
StringReader/StringWriter
입출력 대상이 메모리인 스트림이다. StringWriter에 출려되는 데이터는 내부의 StringBuffer에 저장되며 StringWriter의 다음과 같은 메서드를 이용해서 저장된 데이터를 얻을 수 있다.
StringBuffer getBuffer() // StringWriter에 출력한 데이터가 저장된 StringBuffer를 반환한다.
String toString() // StringWriter에 출력된 (StringBuffer에 저장된) 문자열을 반환한다.
BufferedReader/BufferedWriter
버퍼를 이용해서 입출력의 효율을 높일 수 있도록 해주는 역할을 한다. 버퍼를 이용하면 입출력의 효율이 비교할 수 없을 정도로 좋아지기 때문에 사용하는 것이 좋다.
InputStreamReader/OutputStreamWriter
바이트기반 스트림을 문자기반 스트림으로 연결시켜주는 역할을 한다. 바이트기반 스트림의 데이터를 지정된 인코딩의 문자데이터로 변환하는 작업을 수행한다.
생성자 / 메서드 | 설명 |
InputStreamReader(InputStream in) | OS에서 사용하는 기본 인코딩의 문자로 변환하는 InputStreamReader를 생성한다. |
InputStreamReader(InputStream in, String encoding) | 지정된 인코딩을 사용하는 InputStreamReader를 생성한다. |
String getEncoding() | InputStreamReader의 인코딩을 알려 준다. |
생성자 / 메서드 | 설명 |
OutputStreamReader(OutputStream in) | OS에서 사용하는 기본 인코딩의 문자로 변환하는 OutputStreamWriter를 생성한다. |
OutputStreamReader(OutputStream in, String encoding) | 지정된 인코딩을 사용하는 OutputStreamWriter를 생성한다. |
String getEncoding() | OutputStreamWriter의 인코딩을 알려준다. |
표준 입출력(Standard I/O)
콘솔을 통한 데이터 입력과 콘솔로의 데이터 툴력을 의미한다. 자바에서는 표준 입출력을 위해 3가지 입출력 스트림, System.in, System.out, System.err 을 제공하는데 이들은 자바 어플리케이션의 실행과 동시에 사용할 수 있게 자동적으로 생성되기 때문에 개발자가 별도로 스트림을 생성하는 코드를 작성하지 않고도 사용이 가능하다.
System.in : 콘솔로부터 데이터를 입력받는데 사용 (표준 출력)
System.out : 콘솔로부터 데이터를 출력받는데 사용 (표준 입력)
System.err : 콘솔로부터 데이터를 출력받는데 사용 (표준 입력)
File
자바에서는 File클래스를 통해 파일과 디렉토리를 다룰 수 있도록 하고 있다. 다음은 File 생성자와 경로에 관련된 메서드 들이다.
생성자 / 메서드 | 설명 |
File(String fileName) | 주어진 문자열을 이름으로 갖는 파일을 위한 File인스턴스를 생성한다. 파일 뿐만 아니라 디렉토리도 같은 방법으로 다룬다. 여기서 fileName은 주로 경로(path)를 포함해서 지정해주지만, 파일 이름만 사용해도 되는 데 이 경우 프로그램이 실행되는 위치가 경로(path)로 간주된다. |
File(String pathName, String fileName) File(File pathName, String fileName) |
파일의 경로와 이름을 따로 분리해서 지정할 수 있게 한 생성자. 이 중 두 번째 것은 경로를 문자열이 아닌 File인스턴스인 경우를 위해서 제공된 것이다. |
File(URI uri) | 지정된 uri로 파일을 생성 |
String getName() | 파일이름을 String으로 반환 |
String getPath() | 파일의 경로(path)를 String으로 반환 |
String getAbsolutePath() File getAbsoluteFile() |
파일의 절대경로를 String 으로 반환 파일의 절대경로를 File로 반환 |
String getParent() File getParentFile() |
파일의 조상 디렉토리를 String으로 반환 파일의 조상 디렉토리를 FIle로 반환 |
String getCanonicalPath() File getCanonicalPath() |
파일의 정규경로를 String으로 반환 파일의 정규경로를 FIle로 반환 |
멤버변수 | 설명 |
static String pathSeparator | OS에서 사용하는 경로(path) 구분자. 윈도우 ";" , 유닉스 ":" |
static char pathSeparatorChar | OS에서 사용하는 경로(path) 구분자 윈도우 ";" , 유닉스 ":" |
static String separator | OS에서 사용하는 이름 구분자 윈도우 "\" , 유닉스 "/" |
static char separatorChar | OS에서 사용하는 이름 구분자 윈도우 "\" , 유닉스 "/" |
'개발 > Java' 카테고리의 다른 글
[Java] java.lang 패키지 & util classes (0) | 2021.08.21 |
---|---|
[Java] 내부 클래스(Inner class) (0) | 2021.08.20 |
[Java] 인터페이스(Interface) (0) | 2021.08.18 |
[Java] 추상 클래스(abstract class) (0) | 2021.08.18 |
[Java] 다형성(Polymorphism) (0) | 2021.08.17 |