Java의 정석 3판을 보며 공부한 내용을 정리하였습니다.
남궁성님께 많이 배우고 있습니다.
InputStream과 OutputStream은 모든 바이트기반 스트림의 조상이다.
InputStream의 메서드
int available() : 스트림으로부터 읽어 올 수 있는 데이터의 크기 반환
void close() : 스트림을 닫음으로써 사용하고 있던 자원 반환
boolean markSupported() : 현재위치를 표시. 후에 reset()에 의해 표시한 위치로 다시 돌아갈 수 있다.
(readlimit : 되돌아갈 수 있는 byte의 수)
abstract int read() : 1byte를 읽어 온다(0~255). 더 이상 읽어 올 데이터가 없으면 '-1'반환.
(abstract메서드라서 InputStream의 자손들은 자신의 상황에 알맞게 구현해야 한다.)
int read(byte[] b) : 배열 b의 크기만큼 읽어서, 배열 b의 지정된 위치(off)부터 저장.
(실제로 읽어올 수 있는 데이터가 len개보다 적을 수 있다.)
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() : 스트림의 버퍼에 있는 모든 내용을 출력소스에 쓴다.
(버퍼가 있는 출력스트림의 경우에만 의미가 있다. OutputStream에 정의된 flush()는 아무 일도 하지 않는다.)
abstract void write (int b) : 주어진 값을 출력소스에 쓴다.
void write (byte[] b) : 주어진 배열 b에 저장된 모든 내용을 출력소스에 쓴다.
void write (byte[] b, int off, int len) : 주어진 배열 b에 저장된 내용 중에서 off번째부터 len개 만큼만을 읽어서 출력소스에 쓴다.
프로그램이 종료될 때 사용하고 닫지 않은 스트림을 JVM이 자동적으로 닫아 준다.
하지만, 스트림을 사용하고 난 후에는 반드시 close()를 호출해서 닫아줘야 한다.
단, ByteArrayInputStream과 같이 메모리를 사용하는 스트림과 System.in, System.out과 같은 표준입출력 스트림은 닫지 않아도 된다.
ByteArrayInputStream / ByteArrayOutputStream은 메모리, 즉 바이트배열에 데이터를 입출력 하는데 사용되는 스트림이다.
주로 다른 곳에 입출력하기 전에 데이터를 임시로 바이트배열에 담아서 변환 등의 작업을 하는데 사용된다.
import java.io.*;
import java.util.Arrays;
public class Ex15_1 {
public static void main(String[] args) {
byte[] inSrc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] outSrc = null;
ByteArrayInputStream input = null;
ByteArrayOutputStream output = null;
input = new ByteArrayInputStream(inSrc);
output = new ByteArrayOutputStream();
int data = 0;
while((data = input.read()) != -1) { // read()해서 data에 넣고 그 값이 -1인지 확인.
output.write(data); // void write(int b)
}
outSrc = output.toByteArray(); // 스트림의 내용을 byte배열로 반환
System.out.println("Input Source :" + Arrays.toString(inSrc));
System.out.println("Output Source :" + Arrays.toString(outSrc));
}
}
Input Source :[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Output Source :[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
바이트배열은 사용하는 자원이 메모리밖에 없어서 가비지컬렉터에 의해 자동적으로 자원을 반환하므로 close()로 스트림을 닫지 않아도 된다.
read()와 write(int b)를 사용해서 한 번에 1byte만 읽고 쓰므로 작업 효율이 떨어진다.
import java.io.*;
import java.util.Arrays;
public class Ex15_2 {
public static void main(String[] args) {
byte[] inSrc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] outSrc = null;
byte[] temp = new byte[10];
ByteArrayInputStream input = null;
ByteArrayOutputStream output = null;
input = new ByteArrayInputStream(inSrc);
output = new ByteArrayOutputStream();
input.read(temp, 0, temp.length); // 읽어 온 데이터를 배열 temp에 담는다.
output.write(temp, 5, 5); // temp[5]부터 5개의 데이터를 write한다.
outSrc = output.toByteArray();
System.out.println("Input Source : " + Arrays.toString(inSrc));
System.out.println("temp : " + Arrays.toString(temp));
System.out.println("Output Source : " + Arrays.toString(outSrc));
}
}
Input Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Output Source : [5, 6, 7, 8, 9]
앞선 예제와 달리 byte배열을 사용해서 한 번에 배열의 크기만큼 읽고 썼다.
배열을 이용한 입출력은 작업의 효율을 증가시키므로 가능하면 대상에 따라 알맞은 크기의 배열을 사용하자.
import java.io.*;
import java.util.Arrays;
public class Ex15_3 {
public static void main(String[] args) {
byte[] inSrc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] outSrc = null;
byte[] temp = new byte[4]; // 이전 예제와 다르게 배열크기를 4로 지정
ByteArrayInputStream input = null;
ByteArrayOutputStream output = null;
input = new ByteArrayInputStream(inSrc);
output = new ByteArrayOutputStream();
System.out.println("Input Source : " + Arrays.toString(inSrc));
try {
while(input.available() > 0) {
input.read(temp);
output.write(temp);
// System.out.println("temp : "+ Arrays.toString(temp));
outSrc = output.toByteArray();
printArrays(temp, outSrc);
}
}catch(IOException e) {
}
}// main
static void printArrays(byte[] temp, byte[] outSrc) {
System.out.println("temp : " + Arrays.toString(temp));
System.out.println("Output Source : " + Arrays.toString(outSrc));
}
}
Input Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp : [0, 1, 2, 3]
Output Source : [0, 1, 2, 3]
temp : [4, 5, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7]
temp : [8, 9, 6, 7] // 뒤에 6, 7이 잘못포함됨
Output Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 7]
read()나 write()이 IOException을 발생시킬 수 있어서 try-catch문으로 감싸주었다.
available()은 블락킹(blocking) 없이 읽어 올 수 있는 바이트의 수를 반환한다.
마지막 복사에서 배열의 8과 9만 출력해야 하는데, temp에 남아있던 6, 7까지 출력된 모습이다.
temp의 내용을 지우고 다시 쓴 것이 아니라 덮어쓰기를 했기 때문이다.
앞선 예제에서 temp를 수정하려면 다음과 같이 바꾸면 된다.
// 변경 전
while(input.available() > 0) {
input.read(temp);
output.write(temp);
}
// 변경 후
while(input.available() > 0) {
int len = input.read(temp); // 읽어 온 데이터의 개수 반환
output.write(temp, 0, len); // 읽어 온 만큼만 write
}
Input Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp : [0, 1, 2, 3]
Output Source : [0, 1, 2, 3]
temp : [4, 5, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7]
temp : [8, 9, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 6, 7이 빠짐.
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)을 가진 실제 파일과 연결된 FileOutputStream을 생성한다. 두번째 인자인 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을 생성한다.
'D:\Java\workspace\study\example\src\test.txt' 파일의 내용을 읽어온다.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Ex15_5 {
public static void main(String[] args) throws IOException {
File file = new File("d:\\java\\workspace\\study\\example\\src\\test.txt");
FileInputStream fis = new FileInputStream(file);
int data = 0;
while((data=fis.read()) != -1) {
char c = (char)data;
System.out.print(c);
}
}
}
abcdefg
'D:\Java\workspace\study\example\src\output.txt'으로 "HelloWorld!"를 출력한다.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamRun {
public static void main(String[] args) throws IOException {
File file = new File("d:\\java\\workspace\\study\\example\\src\\output.txt");
FileOutputStream fos = new FileOutputStream(file);
String hi = "HelloWorld!";
fos.write(hi.getBytes());
fos.close();
}
}