본문 바로가기

JAVA

15장- 입출력 I/O 21. 02. 15.

1. 자바에서의 입출력

 

1.1 입출력이란

 

1.2 스트림(stream)

- 어느 한쪽에서 다른 쪽으로 데이터를 전달할 때, 두 대상을 연결하고 데이터를 전송할 연결통로.

- 단방향통신만 가능. (하나의 스트림으로 입출력을 동시에 처리할 수 X)

- 동시에 수행하려면, 입력스트림과 출력스트림 총 2개의 스트림이 필요함.

- Queue와 같은 FIFO구조로 되어있다고 생각하면 됨.

 

1.3 바이트기반 스트림- InputStream, OutputStream

입력스트림 출력스트림 입출력 대상의 종류
FileInputStream FileOutputStream 파일
ByteArrayInputStream ByteOutputStream 메모리(byte 배열)
PipedInputStream PipedOutputStream 프로세스(프로세스간의 통신)
AudioInputStream AudioOutputStream 오디오장치

- 입출력의 단위가 1 byte.

1.4 보조 스트림

- 데이터 입출력 기능은 없지만, 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있음.

-> 스트림을 먼저 생성한 다음에 이를 이용해서 보조스트림을 생성해야 함.

    // 먼저 기반스트림 생성.
	FileInputStream fis = new FileInputStream("test.txt");
	
	// 기반스트림을 이용해서 보조스트림을 생성.
	BufferedInputStream bis = new BufferedInputStream(fis);
    
    bis.read(); // 보조스트림인 BufferedInputStream으로부터 데이터를 읽음.

- 보조스트림 BufferedInputStream은 버퍼만을 제공함.

입력 출력 설명
FilterInputStream FilterOutputStream 필터를 이용한 입출력 처리
BufferedInputStream BufferedOutputStream 버퍼를 이용한 입출력 성능향상
DataInputStream ★ DataOutputStream int, float와 같은 기본형 단위로 데이터 처리
SequenceInputStream - 두 개의 스트림을 하나로 연결
ObjectInputStream ObjectOutputStream 데이터를 객체단위로 읽고 쓰는데 사용. 주로 파일을 이용하며 객체 직렬화와 관련있음
- PrintStream 버퍼를 이용하며, 추가적인 print관련 기능(print, printf, println메서드)
PushbackInputStream - 버퍼를 이용해서 읽어 온 데이터를 다시 되돌리는 기능(unread, push back to buffer)

 

1.5 문자기반 스트림- Reader, Writer

- Java에서는 한 문자를 의미하는 char형이 2 byte이기 때문에 바이트기방의 스트림으로 2 byte인 문자를 처리하는 데는 어려움이 있음.

-> 이를 보안하기 위해 문자기반 스트림 제공됨.

- 문자데이터를 입출력할 때는 바이트기반 스트림 대신 문자기반 스트림을 사용할 것.

 

바이트기반 스트림 문자기반 스트림
FileInputStream
FileOutputStream
FileReader
FileWriter
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
PipedInputStream
PipedOutputStream
PipedReader
PipedWriter
StringbufferInputStream
StringbufferOutputStream
StringbufferReader
StringbufferWriter

보조스트림도 똑같이 InputStream은 Reader로 OutputStream은 Writer로 바꾸면 됨.

 

2. 바이트기반 스트림

2.1 InputStream과 OutputStream

InputStream메서드명 설명
void mark(int readlimit) 현재위치 표시해 둠. 후에 reset()에 의해서 표시해 놓은 위치로 다시 돌아갈 수 있음. readlimit은 되돌아갈 수 있는 byte의 수.
void reset() 스트림에서의 위치를 마지막으로 mark()이 호출되었던 위치로 되돌림.
int available()  
void close()  
boolean markSupported()  
abstract int read()  
int read(byte[] b)  
int read(byte[] b, int off, int len) 최대 len개의 byte를  읽어서, 배열 b의 지정된 위치(off)부터 저장함. 실제로 읽어올 수 있는 데이터가 len개보다 적을 수 있음.
long skip(long n)  
OutputStream메서드명 설명
void close() ★ 입력소스를 닫음으로써 사용하고 있던 자원을 반환함.
void flush() 스트림의 버퍼에 있는 모든 내용을 출력소스에 씀.
abstract void write(int b) 주어진 값을 출력소스에 씀.
void write(byte[] b)  
void write(byte[] b, int off, int len)  

2.2 ByteArrayInputStream과 ByteArrayOutputStream

- 메모리, 즉 바이트배열에 데이터를 입출력 하는데 사용되는 스트림.

- 주로 다른 곳에 입출력하기 전에 데이터를 임시로 바이트배열에 담아서 변환 등의 작업을 하는데 사용됨.

 

2.3 FileInputStream과 FileOutputStream

생성자 설명
FileInputStream(String name)  
FileInputStream(FIle file)  
FileInputStream(FileDescripter fdObj)  
FileOutputStream(String name) 지정된 파일이름을 가진 실제 파일과 연결된 FileOutputStream을 생성
FileOutputStream(String name, boolean append) appnend를 true로 하면, 출력시 기존 파일내용의 마지막에 덧붙임.(이어쓰기) false면, 기존 파일내용을 덮어씀.
FileOutputStream(File file) 파일의 이름을 File인스턴스로 지정해줌.
FileOutputStream(File file, boolean append)  
FileOutputStream(FileDescriptor fdObj) 파일 디스크립터로 FileOutputStream 생성
package chap15;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;

public class FileStreamEx {
	public static void main(String[] args)throws IOException {
		 FileInputStream fis = new FileInputStream("C:\\Users\\bo bo\\Documents\\target.txt");// 예외처리 해야함.
		 FileReader fr = new FileReader("C:\\Users\\bo bo\\Documents\\target.txt");
		 int b = 0;
		 
		 while((b = fis.read()) != -1) {// read() 한번에 1byte씩
			 System.out.println(b + " ::: " + (char)b);
		 }
		 System.out.println("--절취선--");
		 b = 0;
		 while((b = fr.read()) != -1) {// read() 한번에 1char씩
			 System.out.println(b + " ::: " + (char)b);
		 }
		 
		 fis.close();
		 fr.close();
//		 b = fis.read();
//		 System.out.println(b);
		 // read한 번씩 cursor 한 칸씩.
		 // End Of File -1
		 // 0 ~ 255
	}
}

target.txt에

======

abcd

1234

가나다라

======

미리 저장해 둠.

FileStreamEx.java

 

<파일복사 구현하기>

package chap15;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class FileStreamEx2 {
	public static void main(String[] args) throws IOException {
		// 파일 복사 구현하기
		FileInputStream fis = new FileInputStream("C:\\Users\\bo bo\\Documents\\target.txt");
		FileOutputStream fos = new FileOutputStream("C:\\Users\\bo bo\\Documents\\target2.txt", true);
		// 파일의 총 크기= 26 byte
		
		byte[] bArr = new byte[8];
//		fis.read(bArr);
//		System.out.println(Arrays.toString(bArr));
//		System.out.println(fis.available());// 남은 가용 byte 수
		
//		bArr = new byte[8];
//		fis.read(bArr);
//		System.out.println(Arrays.toString(bArr));
//		System.out.println(fis.available());
//		
//		bArr = new byte[8];
//		fis.read(bArr);
//		System.out.println(Arrays.toString(bArr));
//		
//		bArr = new byte[8];
//		fis.read(bArr);
//		System.out.println(Arrays.toString(bArr));
//		
//		bArr = new byte[8];
//		fis.read(bArr);
//		System.out.println(Arrays.toString(bArr));
		
		while(fis.available() > 0) {
			int len = fis.read(bArr);// 읽고
			fos.write(bArr, 0, len); // 쓰고
		}
		fis.close();
		fos.close();
	}
}

fis.read(bArr); 하면 파일복사가 제대로 안 된다. 왜지?

target2.txt에

======

34

가나다라

======

로 저장됨.ㅠ 저 줄을 지워보니 정상적으로

======

abcd

1234

가나다라

======

가 생성되는데...

아무튼 텍스트파일을 다룰 땐 문자기반 스트림인 FileReader/FileWriter를 사용하자.

 

3. 바이트기반의 보조스트림

 

3.1 FilterInputStream과 FilterOutputStream

 

 

3.2 BufferedInputStream과 BufferedOutputStream

 

package chap15;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedOutStreamEx1 {
	public static void main(String[] args) {
		try {
			FileOutputStream fos = new FileOutputStream("123.txt");
			BufferedOutputStream bos = new BufferedOutputStream(fos, 5); // buffer의 크기를 5
			
			for(int i = 65 ; i <= 65+25 ; i++) {
				bos.write(i);
			}
			bos.close(); // fos.close();하면 Z가 출력 안 됨.
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

123.txt

3.3 DataInputStream과 DataOutputStream

- 데이터를 읽고 쓰는데 있어서 8가지 기본 자료형의 단위로 읽고 쓸 수 있다는 장점.

- 출력하는 형식은 각 기본 자료형 값을 16진수로 표현하여 저장함.

- ex) int값을 출력한다면, 4byte의 16진수로 출력.

 

package chap15;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutputStreamEx1 {
	public static void main(String[] args) {
		FileOutputStream fos = null;
		DataOutputStream dos = null;
		try {
			fos = new FileOutputStream("sample.txt");
			dos = new DataOutputStream(fos); // 보조스트림
			dos.writeInt(Integer.MIN_VALUE); // 정수(int)를 작성 4
			dos.writeFloat(20); // float 4
			dos.writeBoolean(true); // boolean 1byte라서 txt파일 크기가 9 byte
			dos.writeLong(10); // 자료형이 가진 크기를 그대로 활용함.
			dos.close();
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
}

sample.txt 생성.

 

package chap15;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class DataInputStreamEx1 {
	public static void main(String[] args) throws IOException {
		DataInputStream dis = new DataInputStream(new FileInputStream("sample.txt"));
		System.out.println(dis.readInt());
		System.out.println(dis.readFloat());
		System.out.println(dis.readBoolean());
		System.out.println(dis.readLong()); // readLong대신 readInt 두 개 쓸 수도 있음
//		System.out.println(dis.readInt());
//		System.out.println(dis.readInt());
		dis.close();
	}
}

DataInputStreamEx1.java

 

package chap15;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class DataInputStreamEx2 {
	public static void main(String[] args) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(baos);
		
		dos.writeInt(10);
		dos.writeFloat(20.f);
		dos.writeBoolean(true);
		dos.write(0);
		dos.write(0);
		dos.write(0);
		dos.write(10); // write 4개가 writeInt
		dos.writeChar('A');
		dos.writeChar('\uac00');
		dos.writeChars("가가가");
		dos.writeUTF("가A"); // utf에선 A를 1바이트 취급
		
		byte[] result = baos.toByteArray();
		// byte -128 ~ 127 > 256가지
		// unsigned, signed
		String[] hex = new String[result.length];
		
		for(int i = 0 ; i < result.length ; i++) {
			if(result[i] < 0) {
				hex[i] = String.format("%02x", result[i] + 256); // -128 ~ -1 을 128 ~ 255로
			}
			else {
				hex[i] = String.format("%02x", result[i]);
			}
		}
		
		System.out.println("10진수: " + Arrays.toString(result));
		System.out.println("16진수: " + Arrays.toString(hex));
	}
}

DataInputStreamEx2.java

- 자바의 자료형인 byte의 범위가 부호 있는 1byte 정수의 범위인 -128~127이기 때문에 -1로 인식함.

-> 그래서 이 256을 더해서 이 값을 0~266사이의 값으로 변환한 것.

- ByteArray스트림을 사용하면 byte단위의 데이터 변환 및 조작이 가능함.

 

3.4 SequenceInputStream

 

3.5 PrintStream

 

4. 문자기반 스트림

 

4.1 Reader와 Writer

 

4.2 FileReader와 FileWriter

 

4.3 PipedReader와 PipedWriter

 

4.4 StringReader와 StringWriter

 

5. 문자기반의 보조스트림

 

5.1 BufferedReader와 BufferedWriter

 

5.2 InputStreamReader와 OutputStreamWriter

- 바이트기반 스트림을 문자기반 스트림으로 연결시켜주는 역함.

- 그리고 바이트기반 스트림의 데이터를 지정된 인코딩의 문자데이터로 변환하는 작업을 수행함.

- 자바의 세계는 문자!

 

package chap15;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

public class InputStreamReaderEx {
	public static void main(String[] args) throws IOException {
		URL url = new URL("https://ncs.go.kr/index.do");
		InputStream is = url.openStream(); // 바이트기반스트림
		InputStreamReader isr = new InputStreamReader(is); // 바이트 > 문자
		BufferedReader br = new BufferedReader(isr); // 보조스트림
		
		String input = "";
		for(int i = 1 ; (input = br.readLine()) != null ; i++) {
			System.out.println(i + ":::" +input);
		}
		br.close();
	}
}

 

InputStreamReaderEx.java

6. 표준입출력과 File

 

6.1 표준입출력 - System.in, System.out, System.err

 

package chap15;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class StandardIOEx3 {
	public static void main(String[] args) throws IOException {
		PrintStream ps = new PrintStream(new FileOutputStream("std_test.txt")); // 보조스트림 사용
		System.setOut(ps); // 보조스트림 변경
		
		System.out.println("헬로우월드1"); // txt파일로 들어감
		System.out.println("헬로우월드2"); // txt파일로 들어감
		System.out.println("헬로우월드3"); // txt파일로 들어감
		System.err.println("헬로우월드");
		
		// 상수
		// 값이 "한번 정해지면" 변하지 않는 것.
		System.out.println(File.separator); // 한번 값이 정해지는 게 요인에 의해 값이 다름. 그래서 소문자.
		// windows \
		// linux /
		
		System.out.println(Integer.MAX_VALUE); // 코드 작성 당시 불변값
		System.out.println(String.CASE_INSENSITIVE_ORDER);
	}
}

 

StandardIOEx3.java

 

6.2 표준입출력의 대상변경 - setOut(), setErr(), setIn()

 

6.3 RandomAccessFile

- 이 클래스의 가장 큰 장점은 파일의 어느 위치에나 읽기/쓰기가 가능하다는 것.

- 내부적으로 파일 포인터를 사용하는데, 입출력 시에 작업이 수행되는 곳이 바로 파일 포인터가 위치한곳이 됨.

 

6.4 File

 

package chap15;

import java.io.File;
import java.io.IOException;

public class FileEx1 {
	public static void main(String[] args) throws IOException {
		File f = new File("D:\\workspace\\chap15\\src\\chap15\\FileEx1.java");
		String fileName = f.getName();
		int pos = fileName.lastIndexOf(".");
		
		System.out.println("경로제외 파일 이름:: " + fileName);
		System.out.println("확장자 제외 파일 이름:: " + fileName.substring(0, pos));
		System.out.println("확장자:: " + fileName.substring(pos+1));
		
		System.out.println("경로 포함 파일이름:: " + f.getPath());
		System.out.println("파일의 절대경로:: " + f.getAbsolutePath());
		System.out.println("파일의 정규경로:: " + f.getCanonicalPath());
		System.out.println("파일이 속해 있는 디렉토리1:: " + f.getParent());
		System.out.println("파일이 속해 있는 디렉토리2:: " + f.getParentFile().getParentFile());
		
		System.out.println();
		
		System.out.println("패스 구분자" + File.pathSeparator);
		System.out.println("구분자" + File.separator);
		System.out.println();
		System.out.println("user dir:: " + System.getProperty("user.dir"));
		System.out.println("sun.boot.class.path:: " + System.getProperty("sun.boot.class.path"));
//		System.getProperties("user.dir");
		
		
		// 소유자
		// 그룹
		// 손님
		
		// 읽기
		// 실행하기
		// 쓰기
		
		// chmod 777 누구에게나 모든 권한 다 줌
		// 		 755 그룹, 손님한텐 쓰기 권한 빼고 줌.
		
	}
}

FileEx1.java

 

 

 

 

'JAVA' 카테고리의 다른 글

16장- 네트워킹 21. 02. 16.  (0) 2021.02.17
15장- 입출력 I/O 끝 21. 02. 16.  (0) 2021.02.17
11장- 컬렉션 프레임웍 21 . 02. 08.  (0) 2021.02.09
04장- 조건문과 반복문 21. 02. 03.  (0) 2021.02.04
21. 01. 27. 03장- 연산자  (0) 2021.01.27