-
[자바의 정석] Ch.15 입출력(I/O)스터디플래너/공부하기 2022. 9. 18. 12:35
1. 자바에서의 입출력
1.1 입출력이란?
- I/O는 입력을 뜻하는 Input과 출력을 뜻하는 Output의 줄임말.
- 입출력은 컴퓨터 내부/외부 장치와 프로그램간의 데이터를 주고받는 것으로 Scanner를 통해 키보드로 데이터를 입력받고 System.out.println()을 이용하여 화면에 출력하는 것이 예시.
1.2 스트림(Stream)
- 스트림은 데이터를 어느 한 쪽에서 다른 쪽으로 전달할 때 두 대상을 연결하고 데이터를 전송할 수 있는 무언가를 뜻함.
- 스트림은 데이터를 운반하는데 사용하는 연결통로로 단방향통신만 가능해 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없음 → 입출력을 위해 입력 스트림과 출력 스트림 ,두 개의 스트림이 필요.
1.3 바이트기반 스트림 - InputStream, OutputStream
- 스트림은 바이트 단위로 데이터를 전송.
- InputStream과 OutputStream은 입출력 대상에 따라 자식 클래스로 다음의 클래스가 있음; 책에는 크게 File(파일), ByteArray(메모리, byte배열), Piped(프로세스), Audio(오디오 장치)가 있는데 AudioInputStream은 패키지가 다르고 AudioOutputStream은 검색해봐도 안 나옴.
InputStream의 Subclasses: AudioInputStream, ByteArrayInputStream, FileInputStream, ObjectInputStream, PIpedInputStream, SequenceInputStream, StringBufferInputStream OutputStream의 Subclasses: ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, PipedOutputStream - InputStream과 OutputStream의 추상메소드로 각각 read()와 write(int b)가 있음
- 메서드 소개란에 추상 메서드 칸을 보면 각각의 추상메서드와 인스턴스 메서드 칸에 추상메서드를 오버로드한 두 개의 메소드가 있음. →추상 메서드가 존재하기에 오버로드 된 두 개의 메서드도 존재함을 기억할 것.
/ 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 // 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
1.4 보조 스트림
- 보조 스트림은 실제로 데이터를 주고 받는 스트림이 아님 → 데이터를 입출력할 수 없음
- 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있음 → 스트림을 생성한 다음 보조 스트림을 생성해야 함
// 스트림 생성 FileInputStream fis = new FileInputStream("text.txt"); // 만든 스트림을 이용하여 보조 스트림 생성 BufferedInputStream bis = new BufferedInputStream(fis); // 보조 스트림으로 데이터를 읽음 bis.read();
- text.txt 파일을 읽기 위해 FileInputStream을 사용하되 BufferedInputStream의 버퍼를 이용하여 성능을 향상시키는 자바의 정석 예제 코드이다. 버퍼는 어떻게 성능을 향상시키나 문서를 찾아보았다; BufferedInputStream을 선언할 때 내부의 버퍼 배열이 생긴다. 스트림에서 바이트를 읽거나 생략할 때마다 내부 버퍼는 포함된 input stream에서 필요한 것들로 한번에 많은 바이트를 다시 채운다. 새로운 바이트를 포함된 input stream에서 가져가기 전에 가장 최근에 작업한 기록작업이 다시 읽음으로써 이 기록작업은 input stream에서 지점을 기억하고 나머지 작업이 읽어온 모든 바이트가 읽게 한다. 문서를 얼렁뚱땅 해석해서 이해가 잘 안 가는데 좀 더 찾아보니 대강 이런 내용인 듯 하다. → FileInputStream은BufferedInputStream보다 큰 용량의 버퍼를 스스로 가질 수 없다. FileInputStream의 참조변수 fis를 BufferedInputStream를 선언하여 이용하면 더 큰 버퍼를 만들 수 있으므로 바이트를 읽고 기억하는데 효과적이다.
1.5 문자기반 스트림 - Reader, Writer
- Java에서 문자 자료형인 char는 2 byte 이지만 바이트기반 스트림은 1byte로 바이트기반 스트림으로 문자를 처리하기 어려움
→ 문자데이터를 입출력할 때 문자기반 스트림을 사용바이트기반 스트림 문자기반 스트림 FileInputStream
FileOutputStreamFileReader
FileWriterByteArrayInputStream
ByteArrayOutputStreamByteArrayReader
ByteArrayWriterPipedInputStream
PipedOutputStreamPipedReader
PipedWriterStringBufferedInputStream(deprecated)StringBufferedOutputStream(deprecated)StringReader
StringWriter- 바이트기반 스트림처럼 문자기반 스트림도 보조스트림이 따로 존재
바이트기반 보조스트림 문자기반 보조스트림 BufferedInputStream
BufferedOutputStreamBufferedReader
BufferedWriterFilterInputStream
FilterOutputStreamFilterReader
FilterWriterLineNumberInputStream(deprecated)LineNumberReader PrintStream PrintWriter PushbackInputStream PushbackReader 2. 바이트기반 스트림
2.1 InputStream과 OutputStream
- 공통으로 있는 close()는 스트림을 닫아주는 메소드로 JVM이 사용하고 닫지 않은 스트림을 닫아주긴 하지만 직접 닫아주는게 좋음
- InputStream의 mark()는 현재 위치를 표시해놓는 메소드로 매개변수로 readlimit을 받아 되돌아갈 수 있는 byte의 수를 받을 수 있고, reset()은 스트림의 위치를 마지막으로 mark()가 호출된 곳으로 돌아감. 두 메소드를 사용하기 전 markSupported()를 이용하여 mark()와 reset()을 지원하는지 알 수 있음.
- flush()는 스트림 버퍼에 있는 모든 내용을 출력 소스에 쓰는데 보조스트림을 이용하지 않아 버퍼가 없는 OutputStream의 flush()는 아무 작업도 하지 않음
2.2 ByteArrayInputStream과 ByteArrayOutputStream
- ByteArrayInputStream과 ByteArrayOutputStream은 이름 그대로 바이트배열로 데이터를 입출력하는데 사용하는 스트림.
- ByteArrayInputStream과 ByteArrayOutputStream은 스트림에서 읽을 수 있는 바이트를 가진 내부 버퍼를 갖고있고 내부 카운터가 read()로 다음 바이트를 추적함.
2.3 FileInputStream과 FileOutputStream
생성자 설명 FileInputStream(String name) Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system. FileInputStream(File file) Creates a FileInputStream by opening a connection to an actual file, the file named by the File object file in the file system. FileInputStream(FileDescriptor fdObj) Creates a FileInputStream by using the file descriptor fdObj, which represents an existing connection to an actual file in the file system. FileOutputStream(String name) Creates a file output stream to write to the file with the specified name. FileOutputStream(String name, boolean append) Creates a file output stream to write to the file with the specified name. append가 true이면 기존 파일 내용의 마지막에 덧붙이기, false이면 기존 파일 내용에 덮어쓰기 FileOutputStream(File file) Creates a file output stream to write to the file represented by the specified File object. FileOutputStream(File file, boolean append) Creates a file output stream to write to the file represented by the specified File object. append가 true이면 기존 파일 내용의 마지막에 덧붙이기, false이면 기존 파일 내용에 덮어쓰기 FileOutputStream(FileDescriptor fdObj) Creates a file output stream to write to the specified file descriptor, which represents an existing connection to an actual file in the file system. * File Descriptor
- File Descriptor는 Unix나 Unix 운영체제에서 파일이나 파이프나 네트워크 소켓과 같은 다른 입출력 자원을 다루는 특별한 구분자이다. File Descriptor는 주로 양의 정수로 음수이면 에러이거나 값이 없는 것이다. PCB에 File Descriptor번호가 등록되면 파일 이름으로 FileInputStream과 FileOutputStream을 생성하듯 File Descriptor번호로 FileInputStream과 FileOutputStream을 생성할 수 있다.
import java.io.FileInputStream; import java.io.IOException; public class FileViewer { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream(args[0]); int data = 0; while ((data=fis.read()) != -1){ char c = (char)data; System.out.print(c); } } }
javac FileViewer.java ; FileViewer.java 컴파일
java FileViewer.java; FileViewer.java를 실행했으나 이 프로그램은 실행할 때 명령어 다음 인자를 매개변수로 받기때문에 이렇게만 입력하면 입력값이 없어 ArrayIndexOutOfBoundsException이 발생
java FileViewer FileViewer.java; 코드를 출력
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileCopy { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream(args[0]); FileOutputStream fos = new FileOutputStream(args[1]); int data = 0; while ((data = fis.read()) != -1){ fos.write(data); } fis.close(); fos.close(); }catch (IOException e){ e.printStackTrace(); } } }
- FileCopy파일을 컴파일한 후 java FileCopy.java FileCopy.java FileCopy.bak 이 명령어를 수행 → FileCopy.bak로 파일을 복사됨
'스터디플래너 > 공부하기' 카테고리의 다른 글
[자바의 정석] Ch.15 입출력(I/O) (1) 2022.10.03 [자바의 정석] Ch.15 입출력(I/O) (1) 2022.10.03 [자바의 정석] Ch.14 람다와 스트림 (0) 2022.09.10 [자바의 정석] Ch.14 람다와 스트림 (0) 2022.09.03 [자바의 정석] Ch.14 람다와 스트림 (0) 2022.08.28