2022-01-17(월) 10주차 1일

Jeongyun Heo·2022년 1월 17일
0

session 1 : io.ex01.Exam0210 ~ Exam0330

모든 데이터는 바이트
UTF-8로 코드화 돼서 저장될 뿐이지 다 바이트

java.io
Provides for system input and output through data streams, serialization and the file system.

serialization : 객체 단위로 읽고 쓰기

file system : 파일과 디렉토리의 위치 정보를 관리하는 시스템

InputStream
This abstract class is the superclass of all classes representing an input stream of bytes.

바이트 스트림을 다루는 모든 클래스의 수퍼클래스

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/InputStream.html

abstract int read() ← 추상메서드
클래스 상속받아서 read() 메서드 반드시 구현해야 됨

이 기능은 반드시 있어야 되지만 서브클래스마다 각각 동작하는 방법이 다르다는거구나

Car를 상속받아서 SUV를 만드는 것도 상속이다. (specialization)

com.eomcs.io.ex01.Exam0210.java

default package

file1.isDirectory() : 디렉토리인지 여부

file1.isFile() : 파일인지 여부

가독성

file1.canExecute() : 읽을 수 있냐. 접근할 수 있냐.

file1.exists() : 파일 존재 여부. 이걸 제일 첫 번째로 하기.

temp 디렉토리를 생성하였습니다.

File dir = new File("temp");
if (dir.mkdir()) { // 디렉토리가 이미 존재하면 리턴값은 false

File 클래스로 디렉토리를 만들 수 있다. 라는 사실만 기억하기

temp2 폴더가 없는데 temp2 하위 폴더 못 만듦
존재하지 않는 폴더 밑에 하위 폴더는 못 만든다.

mkdirs() : 중간 폴더도 다 만든다.

temp2/a/b 디렉토리를 생성하였습니다.

temp 디렉토리를 삭제할 수 없습니다.

하위 디렉토리부터 지워 올라가야 됨

test.txt 파일을 생성하였습니다.

존재하지 않는 폴더에 파일을 생성하려고 하면 에러남

디렉토리가 존재하지 않으면 먼저 디렉토리를 생성하고 파일을 만든다.

프로젝트 폴더(app)가 현재 폴더

list() : 직계 자식까지만 출력

file.lastModified()

java.sql.Date 클래스도 util.Date 클래스의 서브클래스이다.

파일 객체와 파일명 필터의 작업 과정

04-입출력스트림 / 4 페이지

com.eomcs.io.ex01.Exam0610.java

File System에서 파일/디렉토리 정보를 받아온다.

① list()
App. → File 객체에 요청
② 파일 / 디렉토리 정보를 요청
File → File System
③ 파일 정보 목록 리턴
File ← File System

뒤에 확장자가 java인 것만 추출해서 리턴하고 싶음

FilenameFilter ← 파일명을 걸러내는 필터

④ File → FilenameFilter
파일 정보를 1개 넘긴다
해당 폴더에 들어 있는 파일이나 디렉토리를 찾을 때마다 호출

⑤ File ← FilenameFilter
결과에 포함할지 여부를 리턴 (true, false 리턴)

⑥ 포함할 대상이면 배열에 추가한다.
String[] 배열에 추가
list()가 리턴하는 String[] 배열에 포함시켜!

④, ⑤, ⑥ 반복

⑦ App. ← File
파일명 배열 String[] 리턴

흐름 기억하기!

인터페이스 문법

파일 객체와 필터의 관계

04-입출력스트림 / 5 페이지

개발자A가 Filter1을 만들었다
check(파일명) : boolean

개발자B는 Filter2를 만들었다
confirm(파일명) : boolean

개발자C는 Filter3을 만들었다
ok(파일명) : int

파일 객체가 있는데
if (check("a.pdf")) {...}
if (confirm("a.pdf")) {...}
if (ok("a.pdf") == 1) {...}

필터 일을 하는 클래스를 만들 때
개발자마다 사용법(메서드를 호출하는 방법)이 다르다면
필터 사용법이 일관성이 없기 때문에 프로그래밍이 어려워진다.
해결책!
사용법 통일
메서드 호출 규칙을 통일!

그래서 등장한 문법이 인터페이스

인터페이스

04-입출력스트림 / 6 페이지

메서드 호출 규칙을 정의하는 문법
메서드를 만드는 사람에 상관없이 동일한 시그너처(메서드명, 파라미터, 리턴타입)를 갖는 메서드를 정의한다.
그래서 그 메서드를 사용하는 개발자가 일관된 방식으로 사용할 수 있어서 프로그래밍이 쉬워진다.
객체의 교체(대체)가 쉬워진다.

자동차 휠
규칙이 통일
사용자의 실행조건에 따라 다양한 휠로 교제할 수 있다.
제조사에 상관없이

✅ 메서드 규칙을 정의하는 이유
해당 클래스를 만든 개발자에 상관없이 일관된 방법으로 사용할 수 있다!

파일 필터와 인터페이스

04-입출력스트림 / 7 페이지

<<interface>> FilenameFilter
accept(파일명) : boolean

클래스 중에서 규칙을 정의하는 클래스를 인터페이스라고 한다.
인터페이스도 컴파일하면 .class 파일로 됨

파일 이름을 걸러내는 필터 클래스
FilenameFilter 규칙(인터페이스)에 따라 구현해야 한다.

File파일 이름을 걸러내는 필터 클래스
인터페이스에 정의된 규칙에 따라 메서드를 호출한다.

FilenameFilter 인터페이스 구현하기

04-입출력스트림 / 8 페이지

인터페이스 : 규칙을 정의한 거

<<interface>> FilenameFilter
accept(String) : boolean ← 추상메서드

<<concrete>> JavaFilter
accept(String) : boolean {...} ← 구현 메서드
구현한 걸 강조하기 위해 concrete 라고 한다.

class JavaFilter implements FilenameFilter {
  public boolean accept(File dir, String name) {
    // FilenameFilter 규칙에 선언된 대로 정확하게 만들어야 한다!
  }
}

04-입출력스트림 / 9 페이지

🔹 인터페이스
메서드 사용 규칙 / 메서드 호출 규칙 / 객체 사용법을 정의한 문법

객체를 쓴다는 게 메서드를 쓴다는 거

Caller → 인터페이스 → Callee

Caller를 만드는 입장인가?
메서드에 따라서 호출되는 Callee를 만드는 입장인가?
아니면 둘 다 만들어야 하는가?

인터페이스가 이미 존재한다는 것은 그 인터페이스에 따라서 클래스를 만드는 입장

USB 데이터 입출력 규칙이 있으면 그 USB 입출력 규칙에 따라서 연결하는 마우스를 만드느냐 키보드를 만드느냐 웹캡을 만드느냐 아니면 마이크를 만드느냐
아니면 그걸 사용하는 컴퓨터를 만드는 입장이냐
어떤 걸 만드는 입장인지 빨리 판단내려야 된다

3교시 시작

FilenameFilter 인터페이스

04-입출력스트림 / 10 페이지

FilenameFilter 규칙에 따라서 메서드를 누군가가 호출할 건데 누가 호출하냐고

호출하는 애를 만들지 호출당하는 애를 만들지

FilenameFilter 규칙에 따라서 JavaFilter를 만들어야 됨
JavaFilter 클래스는 File 객체가 호출함

caller쪽을 만들어야 되는지 callee쪽을 만들어야 되는지

boolean accept(File dir, String name);

true를 리턴하면 배열에 포함되고, false를 리턴하면 배열에 포함되지 않는다.

list()가 두 종류가 있는데

모든 파일 이름과 디렉토리 이름을 리턴하는 거랑
FilenameFilter 객체 주는 거

String[] list(FilenameFilter filter)
FilenameFilter 라는 규칙에 따라서 만든 객체 주소를 넘겨달라는 거

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/BufferedReader.html

포유류 실체 없음. 특징을 뽑아놓은 추상임. 추상개념.

BufferedReader(Reader in)
Reader 종류를 원하는 거
인스턴스를 만들 수 있는 서브클래스 객체를 원하는 거
인터페이스나 추상클래스는 인스턴스를 만들 수 없다
인터페이스나 추상클래스가 파라미터에 있다는 건
콘크리트 클래스 객체의 주소를 원하는 거

list(FilenameFilter filter)
FilenameFilter 규칙에 따라서 만든 클래스의 객체의 주소를 원하는 거

인터페이스에 선언된 메서드를 구현하고 객체를 만들어서 list를 호출할 때 넘겨준다

폴더 이름에 . 넣을 수 있음

폴더도 나옴

우리가 원하는 건 java 파일이지 java로 끝나는 디렉토리가 아님

파일인지 디렉토리인지 여부는 검사하지 않는다.

디렉토리 정보와 이름을 합쳐 파일 객체를 생성한다.

file.isFile()

콘솔창 출력 잘려서 나오는 거

이클립스 콘솔창에서 마우스 오른쪽 버튼 클릭

80000 → 800000 바꿔주기

com.eomcs.io.ex02

FileOutputStream

OutputStream : byte 출력 스트림

InputStream : byte 단위로 읽는 스트림

write(int) : 1 byte 출력

오직 맨 끝 1바이트만 출력한다.

read(int) : 1 byte씩 읽기

04-입출력스트림 / 12 페이지

com.eomcs.io.ex02.Exam0210.java
Byte Stream - 바이트 배열 출력하기

바이트 배열 단위로 가능

바이트 배열 전체 출력

write(byte[]) : 배열의 값 전체를 출력한다.

write() 메서드에 int 값 주면 맨 끝에 1 byte 출력하고
byte 배열 주소를 주면 바이트 배열 전체를 출력한다.

com.eomcs.io.ex02.Exam0220.java
Byte Stream - 바이트 배열 읽기

빈 배열 준비
100 byte 배열 준비
배열 크기 만큼 읽어서 채운다

read(byte[]) : 읽은 바이트 개수 리턴

com.eomcs.io.ex02.Exam0310.java
Byte Stream - 바이트 배열의 특정 부분을 출력하기

04-입출력스트림 / 13 페이지

write(byte[], 시작인덱스, 출력개수) : 시작 위치부터 지정된 개수를 출력한다.

out.write(bytes, 2, 3)
배열에서 2번부터 3개 바이트 출력

com.eomcs.io.ex02.Exam0320.java
Byte Stream - 읽은 데이터를 바이트 배열의 특정 위치에 저장하기

read(byte[], 저장할 위치, 저장하기를 희망하는 개수)
읽은 데이터를 "저장할 위치"에 지정된 방부터 개수만큼 저장한다.
리턴 값은 실제 읽은 바이트 개수이다.

충분히 큰 배열을 달라는 거
그래서 넉넉하게 100 byte로 만든 거

배열도 기본적으로 다 0으로 초기화된다
Heap에 저장되는 건 다 0으로 초기화된다

in.read(buf, 10, 40)
파일에서 데이터를 읽어 10번 항목부터 채운다. 최대 40개의 값만 채운다.

바이너리 파일
character set(문자표) 규칙에 따라 작성한 파일이 아닌 파일.
기본 텍스트 편집기(메모장, vi 에디터 등)로 편집할 수 없는 파일을 말한다.

텍스트 파일
특정 character set(문자표) 규칙에 따라 작성한 파일.
기본 텍스트 편집기(메모장, vi 에디터 등)로 편집할 수 있는 파일을 말한다.

텍스트 에디터로 편집한 후에도 읽고 쓰는 데 문제가 없으면 텍스트 파일

com.eomcs.io.ex02.Exam0410.java
FileInputStream 활용 - JPEG 파일 읽기

JPEG 파일은 첫 번째 두 바이트가 ff d8로 시작한다

자바 jpeg 라이브러리 사용하면 됨

파일 포맷

04-입출력스트림 / 14 페이지

🔹 파일 포맷 : 데이터를 저장하는 형식

.gif ← GIF 형식에 따라 순차적으로 바이트를 저장한다.
읽을 때, 저장한 형식에 맞춰 읽어야 한다.

형식만 안다면 읽을 수 있다.
몇 바이트부터 몇 바이트까지는 무슨 내용

텍스트를 바이트 스트림으로 출력하기

04-입출력스트림 / 15 페이지

com.eomcs.io.ex02.Exam0510.java
Byte Stream - 텍스트 출력 하기

FileOutputStream으로 텍스트 출력할 수 있음

지구상에 있는 모든 데이터를 FileOutputStream, FileInputStream으로 출력할 수 있다

출력할 수 있는데 좀 불편해서 FileReader, FileWriter 나온 거

지구상에 있는 모든 데이터는 파일에 저장할 때 FileOutputStream, FileInputStream으로 출력하고 읽는다

텍스트를 바이트 스트림으로 출력하기

write() 메서드가 문자열을 자동으로 바이트 배열로 바꿔주지는 않음
파라미터에 문자열을 넣을 수 없다. 문자열을 바이트 배열로 변환하여 넘겨줘야 한다. 내가 직접 바이트 배열을 얻어야 한다.

write(byte[]) : 배열의 값 전체를 출력한다.

"AB가각" 문자열을 byte 배열로 바꿔준다.
byte[] bytes = str.getBytes();

내부에 저장될 때는 41 42 AC00 AC01 (UTF-16)으로 저장된다.

"AB가각" → 41 42 AC00 AC01 (UTF-16)
UTF-16으로 저장하면 읽을 때도 UTF-16으로 읽어야 됨
다 UTF-8을 쓰고 있는데 UTF-16으로 하면 사용할 수 있는 범위가 줄어든다
UTF-16을 그대로 출력해도 되겠지만 선호하지 않는다
더 넓게 통용되는 규칙으로 바꾼다
UTF-8로 바꾼다.
UTF-16으로 출력할 수 없는 게 아니라 출력할 수 있는데
UTF-16으로 저장 못 하는 게 아니라 더 일반적인 규칙으로 바꾸는 거
AB가각 → 41 42 EA B0 80 EA B0 81 (UTF-8)
out.write(bytes)out.write(41 42 EA B0 80 EA B0 81)
배열을 출력하면 8 byte가 파일에 쓰인다
str.getBytes("UTF-8") ← UTF-8 지정해주는 게 좋음
문자집합을 지정하지 않으면 file.encoding에 설정된 문자집합으로 인코딩하여 리턴한다.

문자열을 출력하기 위해서는 개발자가 직접 바이트 배열을 얻어야 한다.
⟹ 불편하다!

FileOutputStream은 그냥 바이트 배열을 출력하는 일을 하는 거지
문자열을 가지고 바이트 배열을 뽑아내는 일은 안 함

com.eomcs.io.ex02.Exam0511.java
Byte Stream - 텍스트 출력 하기

str.getBytes("EUC-KR")

com.eomcs.io.ex02.Exam0512.java

자바에서 쓰는 유니코드
자바에서 쓰는 방식

str.getBytes("UTF-16BE") ← 자바는 이거 씀

com.eomcs.io.ex02.Exam0513.java

str.getBytes("UTF-16LE")

바이트 순서가 뒤집어짐

com.eomcs.io.ex02.Exam0514.java

str.getBytes("UTF-8") ← 추천

String 객체를 UTF-8 규칙에 따라서 byte 배열로 만들어서 리턴

문자열을 바이트 배열로 추출하는 건 getBytes()
UTF-8로 하기
전세계 대부분이 UTF-8로 텍스트 데이터를 주고 받는다

인코딩 : 문자를 UTF-8로 바꾸는 거
디코딩 : UTF-8 데이터를 문자로 바꾸는 거

자바는 UTF-16을 쓴다

FileInputStream
파일 내용을 배열에 읽어오기

04-입출력스트림 / 16 페이지

com.eomcs.io.ex02.Exam0520.java
Byte Stream - 텍스트 데이터 읽기

파일 데이터를 읽어서 바이트 배열에 담는다.
String 객체로 만들 때 네 번째 파라미터에 바이트 배열에 들어 있는 코드 값이 어떤 문자집합의 값인지 알려준다.

read() 메서드가 바이트 배열을 그대로 읽어서 문자열로 바꿀 수 없음

MS949로 인코딩된 텍스트 읽기
영어는 1바이트를 읽으면 되지만, 한글은 2바이트를 읽어야 한다.
조건문 필요

"AB가각" → (UTF-16) 41 42 AC 00 AC 01 → (MS949) 41 42 B0 A1 B0 A2

배열을 준비한다
배열에 담는다
총 6개 바이트 (6 byte)
new String (배열 , "MS949") ← MS949로 되어 있다고 정확하게 알려준다
0041 0042 AC00 AC01 (A B 가 각) 이라는 문자열을 만들 것이다

com.eomcs.io.ex02.Exam0521.java
Byte Stream - 텍스트 데이터 읽기 II

읽은 바이트를 String 객체로 만들어보자.
바이트 배열에 저장된 문자 코드를 JVM이 사용하는 문자 집합(UCS2=UTF16BE)의 코드 값으로 변환한다. String 클래스는 따로 문자집합을 알려주지 않으면 file.encoding에 설정된 문자집합으로 인코딩된 것으로 간주하고 UTF-16으로 바꾼다.

new String(byte[] bytes, int offset, int length, String charsetName)

new String(바이트 배열, 시작, 개수, "문자집합")
배열에 저장된 문자의 인코딩 규칙 (문자집합)

바이트 배열이 어떤 문자집합으로 인코딩된 것인지 알려주지 않으면 file.encoding에 설정된 문자집합으로 인코딩된 것으로 간주한다.

com.eomcs.io.ex02.Exam0522.java

바이트 배열에 MS949 문자집합에 따라 인코딩된 데이터가 들어 있는데,
String 클래스는 UTF-8 문자집합으로 인코딩되었다고 가정하기 때문에
UTF-16으로 정확하게 변환할 수 없는 것이다.

기초를 소홀히 할 수 없음..

0개의 댓글