- 강의
- 57강(stream 사용하여 컬렉션 우아하게 사용하기) ~ 59강(Server-Client 소개와 직렬화/역직렬화)
Java I/O Stream
- 자바 입출력 스트림으로, stream API(collection의 stream)과 다른 개념
- 입력 스트림(Input stream) : 자바 프로그램에서 자료를 읽을 때 사용하는 스트림
- 출력 스트림(Output stream) : 자바 프로그램에서 파일을 저장할 때 사용하는 스트림
- 단위
- 바이트 스트림 : Byte(=1bits) → 자바 초기설정
- 문자 스트림 : Char(=2Byte)
- 1bit는 너무 단위가 적어서 더 큰 단위를 사용
- I/O Stream
- Byte Stream(8bits)
- Input Byte Stream : ...InputStream
- Output Byte Stream : ...OutputStream
- Char Stream(16bits)
- Input Char Stream : ...Reader
- Output Char Stream : ...Writer
- Byte Stream(8bits)
- System
- in, out, err → 정적변수
사용자 입력(Console)
- 사용자 입력받기(Console)
- System.in
- Scanner
더보기
public class Main {
public static void main(String[] args) {
// System.in - 문자 입력
/*
입력값 a = d
출력값 a = 100
출력값 a = d
*/
int a = 0;
System.out.print("입력값 a = ");
try {
a = System.in.read(); // 입력
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("출력값 a = " + a);
System.out.println("출력값 a = " + (char)a);
// System.in - 문자열 입력
/*
입력값 str = hello world!
출력값 str = hello world!
*/
int str = 0;
System.out.print("입력값 str = ");
try {
StringBuilder sb = new StringBuilder();
while ((str = System.in.read()) != '\n') {
sb.append((char)str); // 입력
}
System.out.println("출력값 str = " + sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
// Scanner
/*
입력값 str2 = hellow world~~~~
출력값 str2 = hellow world~~~~
*/
Scanner scanner = new Scanner(System.in);
System.out.print("입력값 str2 = ");
String str2 = scanner.nextLine(); // 입력
System.out.println("출력값 str2 = " + str2);
}
}
File I/O
- File 입출력 - 1Byte
- FileInputStream : 파일 읽기(1Byte)
- FileOutputStream : 파일 출력(1Byte)
- Ascii는 1Byte이고, UTF(한글 지원)은 2Byte
public class Main {
public static void main(String[] args) {
// File read
try (FileInputStream file = new FileInputStream("src/resource/read.txt")) {
int i;
while ((i = file.read()) != -1) { // 파일 읽기
System.out.print((char) i); // 출력
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// File write
String content = "Hello World2222";
// true값을 넣어서 파일이 있으면 파일 내용 뒤에 이어붙이기 함
try(FileOutputStream file = new FileOutputStream("src/resource/write.txt", trur)) {
file.write(content.getBytes()); // 파일 저장
System.out.println("File write complete");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- File 입출력 - 2Byte
- Ascii는 1Byte이고, UTF(한글 지원)은 2Byte
- FileReader : 파일 읽기(2Byte)
- FileWriter : 파일 출력 (2Byte)
public class Main {
public static void main(String[] args) {
// File read
try (FileReader file = new FileReader("src/resource/read.txt")) {
int i;
while ((i = file.read()) != -1) { // 파일 읽기
System.out.print((char) i); // 출력
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// File write
String content = "반갑습니다";
try(FileWriter file = new FileWriter("src/resource/write2.txt")) {
file.write(content); // 파일 저장
System.out.println("File write complete");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Image I/O
- 이미지 입출력
public class Main {
public static void main(String[] args) {
// image path
String path = "src/resource/oak.png";
try {
// image read
File file = new File(path);
BufferedImage image = ImageIO.read(file);
// 이미지 회전
BufferedImage rotatedImage = rotateImage(image, 90);
// 변환된 이미지 저장
String outputPath = "src/resource/oak_rotate.png";
ImageIO.write(rotatedImage, "png", new File(outputPath));
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage rotateImage(BufferedImage image, double angle) {
double radians = Math.toRadians(angle);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
int width = image.getWidth();
int height = image.getHeight();
int newWidth = (int) Math.floor(width * cos + height * sin);
int newHeight = (int) Math.floor(height * cos + width * sin);
BufferedImage rotatedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = rotatedImage.createGraphics();
graphics.translate((newWidth - width) / 2, (newHeight - height) / 2);
graphics.rotate(radians, width / 2, height / 2);
graphics.drawRenderedImage(image, null);
graphics.dispose();
return rotatedImage;
}
}
보조 스트림
- 목적
- 기본 기반 stream 문자열 지원
- 기존 기반 stream 성능 개선
- 기존 메서드를 간편하게 사용할 수 있도록 개선
- 종류
- I/O Stream : 사용자 입출력(console) 개선, 문자열 적용
- InputStreamReader
public class Main { public static void main(String[] args) { // I/O stream // 적용 전 int str = 0; System.out.print("입력값 str = "); try { StringBuilder sb = new StringBuilder(); while ((str = System.in.read()) != '\n') { sb.append((char) str); // 입력 } System.out.println("InputStreamReader 적용전 : " + sb.toString()); } catch (IOException e) { e.printStackTrace(); } // 적용 후 int str2 = 0; System.out.print("입력값 str2 = "); try(InputStreamReader isr = new InputStreamReader(System.in)) { StringBuilder sb = new StringBuilder(); while ((str2 = isr.read()) != '\n') { sb.append((char) str2); // 입력 } System.out.println("InputStreamReader 적용후 : " + sb.toString()); } catch (IOException e) { e.printStackTrace(); } /* 입력값 str = 안녕 InputStreamReader 적용전 : ìë 입력값 str2 = 안녕 InputStreamReader 적용후 : 안녕 */ } }
- InputStreamReader
- Buffered I/O : file 입출력 개선
- BufferedReader
- BufferedWriter
public class Main { public static void main(String[] args) { /* 적용 전 : 9.0ms 적용 후 : 1.0ms */ // Buffered I/O - 적용 전 try (FileReader fr = new FileReader("src/resources/read_long.txt"); FileWriter fw = new FileWriter("src/resources/write_long.txt") ) { double start = System.currentTimeMillis(); int data; while ((data = fr.read()) != -1) { fw.write((char) data); } double end = System.currentTimeMillis(); System.out.println("적용 전 : " + (end - start) + "ms"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // Buffered I/O - 적용 후 try (BufferedReader br = new BufferedReader(new FileReader("src/resources/read_long.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("src/resources/write_long.txt")) ) { double start = System.currentTimeMillis(); int data; while ((data = br.read()) != -1) { bw.write((char) data); } double end = System.currentTimeMillis(); System.out.println("적용 후 : " + (end - start) + "ms"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- PrintWriter : file I/O 성능 개선
- 익숙한 함수인 println(), printf() 매서드 등을 사용할 수 있음
- PrintWriter pw = new PrintWriter(new FileWriter(filePath));
pw.println("hello");
- I/O Stream : 사용자 입출력(console) 개선, 문자열 적용
I/O stream 정리
- 기본
- System.in.read()
- new FileInputStream(파일경로/파일명)
- new FileOutputStream(파일경로/파일명)
- new FileReader(파일경로/파일명)
- new FileWriter(파일경로/파일명)
- 보조
- new Scanner(System.in)
- new InputStreamReader(System.in)
- new BufferedReader(new FileReader(파일경로/파일명))
- new BufferedWriter(new FileWriter(파일경로/파일명))
- new PrintWriter(new FileWriter(파일경로/파일명));
Server-Client
- 네트워크를 통한 정보 전달 시대 → Server-Client 구조
- Client : 데이터를 요청하는 사이드(requset)
- Server : 데이터 요청에 대한 응답하는 사이드(response)
- 구조
- client : server = 1 : N
- 소켓(socket)
- 네트워크 통로 게이트
- server 소켓 오픈 → 오픈된 server 소켓으로 client 소켓 오픈
- server-client socket과 스트림
- respone
- client : output stream
- server : input stream
- requset
- clinet : input stream
- server : output stream
- respone
- socket 프로그래밍 흐름
Server | Client | |||
socket() | 소켓 생성 | 소켓 생성 | socket() | |
bind() | IP, Port 주소 할당 | |||
listen() | 연결대기 | ← ← ← ← ← ← ← ← | 연결 요청 | connet() |
accept() | 수락 | |||
write() | 송신 | → → → → → → → → | 수신 | read() |
read() | 수신 | ← ← ← ← ← ← ← ← | 송신 | write() |
cloase() | 소켓 소멸 | 소켓 소멸 | close() |
- 실습코드 - Server.java
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(5000); // 서버 소켓 생성
) {
System.out.println("서버가 시작되었습니다.");
while (true) {
try (Socket clientSocket = serverSocket.accept()) { // 클라이언트 접속 대기
System.out.println("클라이언트가 접속하였습니다.");
// 클라이언트로부터 데이터를 받기 위한 InputStream 생성
InputStream clientInputStream = clientSocket.getInputStream();
BufferedReader clientBufferedReader = new BufferedReader(new InputStreamReader(clientInputStream));
// 클라이언트로 데이터를 보내기 위한 OutputStream 생성
OutputStream serverOutputStream = clientSocket.getOutputStream();
PrintWriter printWriter = new PrintWriter(serverOutputStream, true);
// inputLine
String inputLine;
// 클라이언트로부터 데이터를 읽고 화면에 출력
System.out.println("클라이언트로부터 온 요청 >> ");
while ((inputLine = clientBufferedReader.readLine()) != null) {
System.out.println(inputLine);
// 클라이언트에게 응답을 보냄
printWriter.println("서버로부터 응답이 왔습니다.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 실습코드 - Client.java
public class Client {
public static void main(String[] args) {
try(Socket socket = new Socket("localhost", 5000)) { // 서버 연결
// 서버로 데이터를 보내기 위한 outputStream 생성
OutputStream outputStream = socket.getOutputStream();
PrintWriter clientPrintWriter = new PrintWriter(outputStream, true);
// 서버로부터 데이터를 받기 위한 inputStream 생성
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 서버에 메세지 전송
clientPrintWriter.println("안녕하세요. 저는 클라이언트 요청입니다.");
// 서버로부터 받은 응답 출력
String response = bufferedReader.readLine();
System.out.println("서버로부터 받은 응답 >>\n " + response);
System.out.println("Client is closed");
} catch (UnknownHostException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
- 실습결과
server | client |
서버가 시작되었습니다. 클라이언트가 접속하였습니다. 클라이언트로부터 온 요청 >> 안녕하세요. 저는 클라이언트 요청입니다. |
서버로부터 받은 응답 >> 서버로부터 응답이 왔습니다. Client is closed |
직렬화/역직렬화
- 직렬화 : java 객체 → Byte 코드
- 역직렬화 : Byte 코드 → java 객체
- 구현
- Serializable 상속
- Object I/O Stream
- transient : 직렬화 대상 제외
- SerialVersionUID : 직렬화 고유 번호 관리
- 구현
public class SerializeExample {
public static void main(String[] args) {
/*
Student 직렬화 : �� sr practice.day20240515.Student���u�7�! I ageL namet Ljava/lang/String;xp t 홍길동
Student 역직렬화 : 홍길동, 20
*/
// 직렬화
byte[] serializedData = null;
Student student = new Student("홍길동", 20);
try (ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
) {
oos.writeObject(student);
oos.flush(); // 적용
serializedData = bao.toByteArray();
System.out.println("Student 직렬화 : " + new String(serializedData));
} catch (IOException e) {
e.printStackTrace();
}
// 역직렬화
try (ByteArrayInputStream bio = new ByteArrayInputStream(serializedData);
ObjectInputStream ois = new ObjectInputStream(bio);
) {
Student student2 = (Student) ois.readObject();
System.out.println("Student 역직렬화 : " + student2.getName() + ", " + student2.getAge());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
class Student implements Serializable {
transient String name; // 직렬화 제외
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 소켓 프로그래밍에 직렬화/역직렬화 코드 구현
'슈퍼코딩 > 주특기(JAVA)' 카테고리의 다른 글
2024.05.17(금) 슈퍼코딩 신입연수원 7주차 Day 5 후기 - 디자인 패턴 (0) | 2024.05.17 |
---|---|
2024.05.16(목) 슈퍼코딩 신입연수원 7주차 Day 4 후기 - 신입 개발자 역량, 메소드 레퍼런스, 멀티 쓰레딩 프로그래밍 (0) | 2024.05.16 |
2024.05.14(화) 슈퍼코딩 신입연수원 7주차 Day 2 후기 - 유틸리티 클래스, 내부 클래스, 람다식, stream (0) | 2024.05.14 |
2024.05.13(월) 슈퍼코딩 신입연수원 7주차 Day 1 후기 - Enum, Optional, DataTime (0) | 2024.05.13 |
슈퍼코딩 신입연수원 6주차 후기 (0) | 2024.05.11 |