자바의 Input과 Ontput에 대해 학습하세요.
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- InputStream과 OutputStream
- Byte와 Character 스트림
- 표준 스트림 (System.in, System.out, System.err)
- 파일 읽고 쓰기
스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
I/O
- 입출력
- 컴퓨터 내부 또는 외부 장치와 프로그램간의 데이터를 주고받는 것
- 키보드로 부터의 데이터 입력
System.out.println()을 이용해 화면에 출력
NIO
- 자바 4부터 새로운 입출력(New Input/Output) java.nio 패키지가 포함됨
- 자바 7로 버전업 하며 기존 IO 와 NIO 사이의 일관성 없는 클래스를 잡고
비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가되었다.
IO vs NIO
구분 | IO | NIO |
입출력 방식 | 스트림 | 채널 |
버퍼 | 넌버퍼 | 버퍼 |
비동기방식 | X | O |
블로킹/넌블로킹 | 블로킹 | 둘 다 지원 |
스트림(Stream)
- 입력에서 출력으로 흐르는 흐름
- 단방향 (= 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다.)
- 여러개를 동시에 보낼 경우 큐 형식 (FIFO) 으로 진행된다.
- 입출력을 동시에 처리하기 위해서는 입력 스트림 / 출력 스트림 2개의 스트림이 필요하다.
- 데이터를 어떤 방식으로 전달하느냐에 따라 2가지로 나뉘어진다.
1. 바이트 스트림 (Byte Stream)
2. 문자 스트림 (Character Stream)
버퍼(Buffer)
- 일반적인 입출력과 다르게, 한 곳에 저장시킨 뒤 한번에 보내는 방식
- API의 호출 횟수를 줄여 입출력 성능을 개선
채널(Channel)
- 한 개 이상의 확실한 입출력 작업을 수행할 수 있는 개방된 연결
- 비동기적으로 입출력을 동시에 진행 가능
InputStream과 OutputStream
InputStream
- 바이트 기반의 입력 스트림의 최상위 클래스 (추상 클래스)
- 모든 바이트 기반 입력 스트림은 이 클래스를 상속받아 만들어진다.
InputStream의 메소드
java.io.InputStream
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException {...};
public int read(byte b[], int off, int len) throws IOException {...};
int read()
- 1 byte를 읽어온다.
- 리턴타입은 int 이다 (= 4byte)
- 1 byte의 데이터는 int형 4byte의 마지막에 들어간다.
- 읽어올 값이 없으면 -1을 리턴한다.
package streamex;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ByteStreamTest {
public static void main(String[] args) {
int count = 0;
try {
int i = 0;
InputStream inputStream = new FileInputStream("a.txt");
while ((i = inputStream.read()) != -1){
System.out.print((char) i);
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println();
System.out.println(count);
}
}
// acdsfdsfsdf
// 11
int read(byte b[])
- 1 byte씩 이아니라 지정해준 byte[] 크기씩 읽어온다.
- 읽어온 값은 int형으로 byte[]에 저장된다.
- 메서드 리턴은 실제 읽은 바이트 수를 리턴한다.
package streamex;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ByteStreamTest {
public static void main(String[] args) {
int count = 0;
try {
int ReadByte;
byte[] size = new byte[5];
InputStream inputStream = new FileInputStream("a.txt");
while ((ReadByte = inputStream.read(size)) != -1){
for (byte b : size) {
System.out.print((char) b);
}
System.out.print("이번 루프에 읽은 바이트 수 : "+ReadByte);
System.out.println();
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("루프 횟수 : "+count);
}
}
// acdsf이번 루프에 읽은 바이트 수 : 5
// dsfsd이번 루프에 읽은 바이트 수 : 5
// fsfsd이번 루프에 읽은 바이트 수 : 1
// 루프 횟수 : 3
int read(byte b[], int off, int len)
- 지정한 바이트만큼 읽어와서 b[]의 offset 인덱스 부터 b[]에 저장하는데 len의 갯수만큼 저장한다.
- 리턴값은 읽어온 갯수이며 len과 같다. 마지막이라 len개를 채우지 못하면 읽어온 갯수를 리턴한다.
package streamex;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ByteStreamTest {
public static void main(String[] args) {
int count = 0;
try {
int ReadByte;
byte[] size = new byte[5];
InputStream inputStream = new FileInputStream("a.txt");
while ((ReadByte = inputStream.read(size,1,3)) != -1){
for (byte b : size) {
System.out.print((char) b);
}
System.out.print("이번 루프에 읽은 바이트 수 : "+ReadByte);
System.out.println();
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("루프 횟수 : "+count);
}
}
// acd 이번 루프에 읽은 바이트 수 : 3
// sfd 이번 루프에 읽은 바이트 수 : 3
// sfs 이번 루프에 읽은 바이트 수 : 3
// dfs 이번 루프에 읽은 바이트 수 : 2
// 루프 횟수 : 4
- 마지막 읽은 바이트 수는 2개지만 dfs가 출력된 이유
매개변수로 전달된 배열은 매번 루프마다 초기화되는 것이 아니라
하나씩 바꾸기 때문에 뒤의 s는 아직 갱신되지 못한 위의 값을 그대로 들고 있다.
이외의 메서드
- int available() : 읽어올 수 있는 바이트 반환
- void close() : 자원을 닫는다. Closable 인터페이스를 구현해야 한다. 되도록 try-with-resource 를 쓰자.
- void mark(int readlimit) : 스트림에서 현재 위치를 마크한다. reset() 을 이용해서 다시 이 위치로 올 수 있다. 매개변수 readlimit 은 마크 이후 readlimit 만큼의 바이트 이후 마크가 사라진다.
- void reset() : 최근에 마크한 곳으로 돌아간다.
- long skip(long n) : n 바이트만큼 건너뛴다.
OutputStream
- 바이트 단위 출력 스크림을 위한 클래스들의 최상위 추상 클래스
OutputStream의 메소드
java.io.OutputStream
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException {...}
public void write(byte b[], int off, int len) throws IOException {...}
public void flush() throws IOException {}
void write(int b)
- 매개변수로 들어온 값을 출력 스트림으로 보낸다.
- 매개변수가 int 라 4byte로 보이지만, byte 자료형 1byte만 보내진다.
package streamex;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class ByteOutputStreamTest {
public static void main(String[] args) {
try {
OutputStream outputStream = new FileOutputStream("abc.txt");
byte[] name = "daseul".getBytes();
for (byte b : name) {
outputStream.write(b);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// abc.txt
// daseul
void write(byte b[])
- 인자로 넘어온 byte 배열의 모든 바이트를 출력 스트림으로 보낸다.
package streamex;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class ByteOutputStreamTest {
public static void main(String[] args) {
try {
OutputStream outputStream = new FileOutputStream("abc.txt");
byte[] name = "daseul".getBytes();
outputStream.write(name);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// abc.txt
// daseul
void write(byte b[], int off, int len)
- b[off] 부터 len개의 바이트를 출력 스트림으로 보낸다.
flush()
- 출력 스트림은 내부에서 버퍼를 사용한다.
- I/O의 횟수를 줄이기 위해 출력하기 전에 버퍼에서 쌓여있다가 순서대로 한꺼번에 출력된다.
- 출력 스트림 버퍼에 있는 내용을 강제로 출력 스트림으로 보낸다.
- OutputStream은 다 쓰면 flush(), close()를 호출해야 한다.
- flushable 인터페이스를 구현하고 있다.
close()
- 자원을 사용하고 닫는다.
- 내부적으로 flush()를 호출한다. 하지만 따로 flush()도 써주는게 좋다.
- try-with-resource를 쓰자
Reader와 Writer
Reader
- 문자 기반 입력 스트림의 최상위 추상 클래스
Reader의 주요 메서드
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
public int read(char cbuf[]) throws IOException
{
return read(cbuf, 0, cbuf.length);
}
abstract public int read(char cbuf[], int off, int len) throws IOException;
int read()
- 입력 스트림으로부터 한 개의 문자 (2 Byte)를 읽고 4byte int 타입으로 리턴
- 영어 1 바이트 / 한글 2 바이트
- 한글 두 글자를 입력 받으려면? read() 두번 호출
- 읽어올 것이 없으면 -1을 리턴한다.
package streamex;
import java.io.FileReader;
import java.io.Reader;
public class ReaderTest {
public static void main(String[] args) throws Exception {
Reader reader = new FileReader("abc.txt");
int readData;
int readCount = 0;
while ((readData = reader.read()) != -1) {
System.out.print((char) readData);
readCount++;
}
System.out.println();
System.out.println("읽어온 횟수 : " + readCount);
}
}
// 다슬
// 읽어온 횟수 : 2
int read(char cbuf[])
- 한 번의 입력 스트림에 cbuf 문자배열의 크기만큼 읽는다.
- 읽어올 문자가 없으면 -1을 반환한다.
- 배열을 매번 초기화하지 않기 때문에, 마지막에 읽어올 때 읽어온 문자 나머지 배열 부분에는 이전 문자열이 남아있을 수 있다.
- 문자의 양이 많을 때는 위 read() 대신 이것을 쓰는것이 좋다.
package streamex;
import java.io.FileReader;
import java.io.Reader;
public class ReaderTest {
public static void main(String[] args) throws Exception {
Reader reader = new FileReader("abc.txt");
int readData;
int readCount = 0;
char[] chars = new char[10];
while ((readData = reader.read(chars)) != -1) {
for (char aChar : chars) {
System.out.print((char) aChar);
}
System.out.println();
System.out.println("읽어온 문자 수 : " +readData);
readCount++;
}
System.out.println();
System.out.println("읽어온 횟수 : " + readCount);
}
}
// 출력 스트림은 내부
// 읽어온 문자 수 : 10
// 에서 버퍼를 사용한
// 읽어온 문자 수 : 10
// 다. 버퍼를 사용한
// 읽어온 문자 수 : 2
// 읽어온 횟수 : 3
int read(char cbuf[], int off, int len)
- 추상메서드
- 입력 스트림으로 부터 len개의 문자만큼 읽고 매개값으로 주어진 문자 배열 cbuf[]에
cbuf[off] ~ cbuf[off+len-1] 까지 저장한다. - 리턴값은 읽어온 문자 수이고, 읽을 문자가 없으면 -1을 반환한다.
Writer
- 문자 기반 출력 스트림의 최상위 추상 클래스
Writer의 메소드
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}
abstract public void write(char cbuf[], int off, int len) throws IOException;
public void write(String str) throws IOException {
write(str, 0, str.length());
}
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
if (len <= WRITE_BUFFER_SIZE) {
if (writeBuffer == null) {
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
cbuf = writeBuffer;
} else { // Don't permanently allocate very large buffers.
cbuf = new char[len];
}
str.getChars(off, (off + len), cbuf, 0);
write(cbuf, 0, len);
}
}
abstract public void flush() throws IOException;
보조 스트림
- 스트림의 기능을 보완하기 위해 제공
- 실제 데이터를 주고받는 스트림이 아니기 때문에 데이터를 입출력할 수 있는 기능은 없지만,
스트림의 기능을 향상 시키거나 새로운 기능을 추가할 수 있다. - 스트림을 먼저 생성한 후 이를 보조 스트림을 생성하여 활용한다.
Buffer을 사용하면 좋은 이유?
- 속도가 빨라진다.
OS 레벨에 있는 시스템 콜의 횟수 자체를 줄이기 때문에 성능이 향상된다. - test.txt라는 파일을 읽기 위해 FileInputStream을 사용할 때,
입력 성능을 향상시키기 위하여 버퍼를 사용하는 보조스트림인 BufferdInputStream을 사용할 수 있다.
// 먼저 기반 스트림을 생성한다.
FileInputStream fileInputStream = new FileInputStream("test.txt");
// 기반 스트림을 이용해 보조 스트림을 생성한다.
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// Buffered**Stream 생성 시 사이즈도 정의하여 생성할 수 있다. (2번째 파라미터)
// default : 8192
BufferedInputStream bis =
new BufferedInputStream(fileInputStream, 8192);
// 보조스트림을 이용해 데이터를 읽는다.
bufferedInputStream.read();
- 보조 스트림인 BufferdInputStream이 입력 기능을 수행하는 것처럼 보이지만,
실제 입력 기능은 BufferdInputStream과 연결된 FileInputStream이 수행한다.
java.io - 데코레이터 패턴
- 자기 자신을의 타입을 감싸는 패턴
- 객체의 추가적인 요건을 동적으로 첨가한다.
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다. - java.io 패키지는 데코레이터 패턴으로 만들어졌다.
- A 클래스에서 B 클래스를 생성자로 받아와서, B 클래스에 추가적인 기능을 덧붙여 제공하는 패턴
BufferedReader 클래스
private Reader in;
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
- BufferedReader는 Reader의 하위 클래스중 하나를 받아와서
버퍼를 이용한 기능을 추가한 기능을 제공한다. - BufferedReader처럼 출력을 담당하는 래퍼 클래스는 출력을 하는 주체가 아니라 도와주는 역할이다.
- Stream을 사용한 클래스에서 이렇게 도와주는 클래스를 보조 스트림 이라고 한다.
보조스트림의 종류
입력 | 출력 | 설명 |
FilterInputStream | FilterOutputStream | 필터를 이용한 입출력 처리 |
BufferedInputStream | BufferedOutputStream | 버퍼를 이용한 입출력 성능 향상 |
DataInputStream | DataOutputStream | int, float 과 같은 Primitive Type으로 데이터를 처리하는 기능 |
SequenceInputStream | SequenceOutputStream | 두개의 스트림을 하나로 연결 |
LineNumberInputStream | LineNumberOutputStream | 읽어온 데이터의 라인번호를 카운트 (jdk 1.1 부터 LineNumberReader로 대체) |
ObjectInputStream | ObjectOutputStream | 데이터를 객체단위로 읽고 쓰는데 사용 주로 파일을 이용하며 객체 직렬화와 관련 |
X | PrintStream | 버퍼를 이용하여, 추가적인 print관련 기능 (print, printf, println 메서드) |
PushBackInputStream | X | 버퍼를 이용하여 읽어온 데이터를 다시 되돌리는 기능 (unread, push to buffer) |
Byte와 Character 스트림
스트림의 객체도
- ByteStream - InputStream / OutputStream
- StringSrteam - Reader / Writer
- 한글을 8bit Stream을 통해서 읽어들인다면 한글이 깨지는 현상이 발생 (16bit와 함께 사용해야 한다)
- 자바에서는 8bit / 16bit Stream을 연결해주는 InputStreamReader 와같은 클래스를 제공해 준다.
- InputSteamReader가 중간에서 인코딩해주는 역할을 수행하여 한글을 정상적으로 읽어올 수 있다.
표준 스트림 (System.in, System.out, System.err)
- 콘솔을 통한 데이터 입력과 콘솔로의 데이터 출력을 의미
- 자바에서는 표준 입출력을 위해 3개지 입출력 스트림을 제공
System.in
System.out
System.err
이들은 자바 어플리케이션 실행과 동시에 사용할 수 있게 자동적으로 생성되기 때문에 개발자가 별도로 스트림을 생성하는 코드를 작성하지 않아도 된다.
System 클래스
- in, out, err은 System 클래스에 선언된 클래스변수 (static) 이다.
public final static InputStream in = null;
...
public final static PrintStream out = null;
...
public final static PrintStream err = null;
- 선언부만 봐서는 in, out, err 타입이 InputStream, PrintStream 이지만
실제로는 버퍼를 이용하는 BufferedInputStream과 BufferedOutputStream 인스턴스를 사용한다.
/**
* Create PrintStream for stdout/err based on encoding.
*/
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
if (enc != null) {
try {
return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
} catch (UnsupportedEncodingException uee) {}
}
return new PrintStream(new BufferedOutputStream(fos, 128), true);
}
표준입출력의 대상 변경 - setOut(), setError(), setIn()
- 해당 함수를 사용 시,
입출력을 콘솔 이외의 다른 입출력 대상으로 변경하는 것이 가능하다.
메서드 | 설명 |
static void setOut(PrintStream out) | System.out의 출력을 지정된 PrintStream으로 변경 |
static void setErr(PrintStream err) | System.err의 출력을 지정된 PrintStream으로 변경 |
static void setIn(InputStream in) | System.in의 입력을 지정한 InputStream으로 변경 |
package streamex;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class SystemTest {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("a.txt");
PrintStream ps = new PrintStream(fos)){
System.setOut(ps); // System.out의 출력 대상을 a.txt 파일로 변경
System.out.println("out - test out");
System.err.println("out - test err");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// console
// out - test err
// a.txt
// out - test out
직렬화 (Serialization)
- 객체를 데이터 스트림으로 만드는 것
- 객체에 저장된 데이터를 스트림에 쓰기 위해 연속적인 (serial) 데이터로 변환하는 것을 의미
- 반대로 스트림으로부터 데이터를 읽어 객체를 만드는 것을 역직렬화(deserialization) 이라고 한다.
ObjectInputStream, ObjectOutputStream
- 직렬화(스트림에 객체를 출력) 시에는 ObjectInputStream 사용
- 역직렬화(스트림으로부터 객체를 입력) 시에는 ObjectOutputStream 사용
- InputStream, OutputStream을 직접 상속받지만 기반스트림을 필요로 하는 보조스트림이다.
그러므로, 객체를 생성할 때 입출력할 스트림을 지정해주어야 한다.
ObjectInputStream(InputStream in)
ObjectOutputStream(OutputStream in)
직렬화가 가능한 클래스 만들기 - Serializable, transient
- 모든 객체가 직렬화 / 역직렬화가 가능하지 않다.
가능한 클래스로 만들어주어야 한다. - 직렬화가 가능한 클래스를 만드려면 java.io.Serializatble 인터페이스를 구현하면 된다.
public class UserInfo implements java.io.Serializable{
String name;
String password;
int age;
}
try(FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(new Userinfo());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try(FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis)) {
UserInfo userinfo = (UserInfo) ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
- 상속받고 있는 특정 클래스가 직렬화를 구현하였다면,
자식클래스는 별도로 직렬화를 구현하지 않아도 자연스럽게 직렬화 가능 - 조상클래스가 직렬화를 구현하지 않고 자식클래스에서만 구현했다면
조상클래스에 정의된 인스턴스 변수는 직렬화 대상에서 제외된다. - 직렬화를 구현하고 있지만 이 클래스 내부 인스턴스 변수가 직렬화할 수 없는 객체를 참조한다면
NotSerializableException이 발생한다. - 객체가 직렬화될 때 클래스에 정의된 멤버들의 정보를 이용하여 serialVersionUID 라는 클래스 버전을
자동 생성하여 직렬화 내용에 포함한다.
역직렬화 시 클래스의 버전을 비교하고 직렬화할 때의 클래스버전과 일치하는지 비교 가능하다.
클래스 내에 serialVersionUID를 정의해주면, 클래스의 내용이 바뀌어도 클래스의 버전이 자동생성된 값으로 변경되지 않는다.
public class ByteStreamCopyFile implements Serializable{
private static final long serialVersionUID = 1L;
...
}
Transient
- transient 제어자를 붙여 직렬화 대상에서 제외할 수 있다.
- 제외시킨 후 역직렬화하면 값은 null
public class UserInfo implements java.io.Serializable{
String name;
transient String password;
int age;
transient Object obj = new Object();
}
파일 읽고 쓰기
File 클래스
- 파일의 크기, 속성, 이름 등의 정보를 얻어내는 기능 / 파일의 생성 및 삭제 기능을 제공
- 디렉토리를 생성하고 디렉토리에 존재하는 파일 리스트를 얻어내는 기능 존재
- 파일의 데이터를 읽고 쓰는 기능은 지원하지 않는다.
File 데이터의 입출력은 Stream이 담당한다. (FileInputStream/FileOutputStream)
File file = new File("C:/Temp/file.txt");
File file = new File("C:\\Temp\\file.txt");
- File 객체를 생성했다고 해서 파일이나 디렉토리가 생성되는 것은 아니다.
생성자 매개값으로 주어진 경로가 유효하지 않더라도 컴파일에러나 예외가 발생하지 않는다.
실제로 파일이나 디렉토리가 있는지 확인하기 위하여 exist() 매소드를 호출하여 확인한다.
boolean isExist = file.exist();
파일 또는 디렉토리를 생성하는 메소드
리턴타입 | 메소드 | 설명 |
boolean | createNewFile() | 새로운 파일 생성 |
boolean | mkdir() | 새로운 디렉토리 생성 |
boolean | mkdirs() | 경로상에 없는 모든 디렉토리 생성 |
boolean | delete() | 파일 또는 디렉토리 삭제 |
파일 또는 디렉토리의 정보를 얻는 메소드
FileInputStream
- 파일로부터 바이트 단위로 읽어들일 때 사용하는 바이트 기반 입력 스트림
- 바이트 단위로 읽기 때문에 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 읽을 수 있다.
// 첫번째 방법
FileInputStream fis = new FileInputStream("C:/Temp/image.gif");
// 두번째 방법
File file = new File("C:/Temp/image.gif");
FileInputStream fis = new FileInputStream(file);
FileOutputStream
- 바이트 단위로 데이터를 파일에 저정할 때 사용하는 바이트 기반 출력 스트림
- 바이트 단위로 저장하기 때문에 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 저장할 수 있다.
// 첫번째 방법
FileOutputStream fos = new FileOutputStream("C:/Temp/image.gif");
// 두번째 방법
File file = new File("C:/Temp/image.gif");
FileOutputStream fos = new FileOutputStream(file);
- 파일이 이미 존재할 경우, 데이터를 출력하면 파일을 덮어쓰게 되므로 기존 내용은 사라진다.
기존 파일 내용 끝에 네이터를 추가하고자 하는 경우
FileOutputStream 생성자의 두번 째 매개값을 true로 생성한다.
FileOutputStream fos = new FileOutputStream("C:/Temp/image.gif", true);
FileOutputStream fos = new FileOutputStream(file, true);
예제 - 파일 복사하기
package streamex;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamCopyFile {
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("a_copy.txt")) {
int readByteNum;
byte[] readBytes = new byte[100];
while ((readByteNum = fis.read(readBytes)) != -1) {
fos.write(readBytes,0,readByteNum);
}
fos.flush();
System.out.println("복사 완료");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader
- 텍스트 파일을 프로그램으로 읽어들일 때 사용하는 문자 기반 스트림
- 문자 단위로 읽기 때문에 텍스트가 아닌 그림 오디오 비디오 등의 파일은 읽을 수 없다.
// 첫번째 방법
FiileReader fr = new FileReader("C:/Temp/file.txt");
// 두번째 방법
File file = new File("C:/Temp/file.txt");
FileReader fr = new FileReader(file);
FileWriter
- 텍스트 데이터를 파일에 저장할 때 사용하는 문자 기반 스트림
- 문자 단위로 저장하기 때문에 텍스트가 아닌 데이터는 파일로 저장할 수 없다.
- FileWriter를 생성하면 저장한 파일이 이미 존재할 경우 그 파일을 덮어쓰게 되므로
기존 내용이 사라지게 된다.
기존 파일 내용 끝에 추가하고자 한다면 FileWriter 생성 시 두번째 매개값을 true로 전달한다.
// 첫번째 방법
FileWriter fw = new FileWriter("C:/Temp/file.txt");
// 두번째 방법
File file = new File("C:/Temp/file.txt");
FileWriter fw = new FileWriter(file);
FileWriter fw = new FileWriter("C:/Temp/file.txt", true);
FileWriter fw = new FileWriter(file, true);
예제 - 파일 복사하기
package streamex;
import java.io.*;
public class ByteStreamCopyFile {
public static void main(String[] args) throws IOException {
try(BufferedReader br = new BufferedReader(new FileReader("b.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b_copy.txt"))){
String line = "";
byte[] readBytes = new byte[10];
while ((line = br.readLine()) != null) {
bw.write(line);
}
}
}
}
'Back-end > java' 카테고리의 다른 글
스터디 15주차 - 람다식 (0) | 2021.07.08 |
---|---|
스터디 14주차 - 제네릭 (0) | 2021.07.08 |
스터디 12주차 - 어노테이션 (0) | 2021.07.06 |
스터디 11주차 - Enum (0) | 2021.07.05 |
스터디 10주차 - 멀티쓰레드 프로그래밍 (0) | 2021.07.02 |