[이것이 자바다] 18장 정리

자바에서 데이터 입출력에 필요한 스트림을 활용하는 방법에 대해 다루었습니다. 입력 스트림과 출력 스트림을 통한 데이터 입출력, 바이트 출력 스트림의 최상위 클래스인 OutputStream, 바이트 입력 스트림의 최상위 클래스인 InputStream, 문자 출력 스트림의 최상위 클래스인 Writer, 문자 입력 스트림의 최상위 클래스인 Reader 등이 포함됩니다. 또한, 보조 스트림, 직렬화와 역직렬화, 파일 및 폴더 생성과 삭제, 파일 시스템에 대한 작업 등에 대해서도 설명하였습니다.
Jan 22, 2024
[이것이 자바다] 18장 정리

WriteExam.java

package ch18; import java.io.FileOutputStream; import java.io.OutputStream; public class WriteExam { public static void main(String[] args) throws Exception { OutputStream os = new FileOutputStream("C:/Temp2/test1.txt"); //데이터 도착지 지정 byte a = 10; byte b = 20; byte c = 30; os.write(a); os.write(b); os.write(c); os.flush(); //버퍼를 비움 os.close(); //사용한 메모리 해제 } }
 

핵심 키워드

  • 데이터는 키보드를 통해 입력될 수도 있고, 파일 또는 프로그램으로부터 입력될 수도 있다. 반대로 데이터는 모니터로 출력될 수도 있고, 파일에 저장되거나 다른 프로그램으로 전송될 수 있다.
  • 자바는 입력 스트림과 출력 스트림을 통해 데이터를 입출력한다. 스트림은 단방향으로 데이터가 흐르는 것이다.
  • OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다. 모든 바이트 출력 스트림은 OutputStream 클래스를 상속받아서 만들어진다.
 

ReadExam.java

package ch18; import java.io.FileInputStream; import java.io.InputStream; public class ReadExam { public static void main(String[] args) throws Exception { InputStream is = new FileInputStream("C:/Temp2/test1.txt"); while (true) { int data = is.read(); if (data == -1) break; System.out.println(data); } is.close(); } }
 

핵심 키워드

  • InputStream은 바이트 입력 스트림의 최상위 클래스로 추상 클래스이다. 모든 바이트 입력 스트림은 InputStream클래스를 상속받아서 만들어진다.
 

WriterExam.java

package ch18; import java.io.FileWriter; import java.io.Writer; public class WriterExam { public static void main(String[] args) throws Exception { Writer writer = new FileWriter("C:/Temp2/test2.txt"); char a = 'A'; writer.write(a); char b = 'B'; writer.write(b); char[] arr = { 'A', 'B', 'C', 'D', 'E' }; writer.write(arr, 2, 3); writer.write("FG"); writer.flush(); writer.close(); } }
 

핵심 키워드

  • 바이트 출력 스트림인 OutputStream에 대응하는 문자 출력 스트림으로 Writer가 있다. writer는 문자 출력 스트림의 최상위 클래스로 추상 클래스이다. 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어진다.
  • Writer는 OutputStream과 사용 방법은 동일하지만 출력 단위가 문자이다.
 

ReaderExam.java

package ch18; import java.io.FileReader; import java.io.Reader; public class ReaderExam { public static void main(String[] args) throws Exception { try { Reader reader = new FileReader("C:/Temp2/test2.txt"); char[] arr = new char[100]; while(true) { int data = reader.read(); if(data == -1) break; for(int i=0; i<arr.length; i++) { System.out.println(arr[i]); } } reader.close(); }catch(Exception e){ e.printStackTrace(); } } }
 

핵심 키워드

  • 바이트 입력 스트림인 InputStream에 대응하는 문자 입력 스트림으로 Reader가 있다. Reader는 문자입력 스트림의 최상위 클래스로 추상 클래스이다. 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어진다.
  • Reader는 InputStream과 사용 방법은 동일하지만 입력 단위가 문자이다.
 

StringExam.java

package ch18; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Scanner; public class StringExam { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String str = reader.readLine(); System.out.println(str); } }

CharConvertExam.java

package ch18; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; public class CharConvertExam { public static void main(String[] args) { try { OutputStream os = new FileOutputStream("C:/Temp2/test3.txt"); Writer writer = new OutputStreamWriter(os, "UTF-8"); writer.write("문자 변환 스트림을 사용합니다."); writer.flush(); writer.close(); FileInputStream is = new FileInputStream("C:/Temp2/test3.txt"); // 기본 바이트 입력 스트림 Reader reader = new InputStreamReader(is, "UTF-8"); // Reader로 변환해주는 보조스트림 char[] data = new char[100]; int num = reader.read(data); // 배열 용량만큼 데이터 읽어오고, 읽어온 데이터 수를 리턴 String str = new String(data, 0, num); // 문자 배열의 오프셋(data)에서 길이만큼 문자로 생성 System.out.println(str); } catch (Exception e) { e.printStackTrace(); } } }
 

핵심 키워드

  • 보조 스트림이란 다른 스트림과 연결되어 여러 가지 편히한 기능을 제공해주는 스트림을 말한다. 보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.
  • InputStream을 Reader로 변환하려면 InputStreamReader 보조 스트림을 연결한다.
  • OutStream을 Writer로 변환하려면 OutputStreamWriter 보조 스트림을 연결한다.
  • BufferedReader 보조 스트림을 연결해서 입출력 성능을 향상시킬 수 있다.
 

FileCopyExam.java

package ch18; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; public class FileCopyExam { public static void main(String[] args) { // System.out.println(originalPath); try { String originalPath = FileCopyExam.class.getResource("image.jpg").getPath(); // url이라는 객체를 getpath() 메소드를 통해 경로로 변경한다. FileInputStream fis = new FileInputStream(originalPath); FileOutputStream fos = new FileOutputStream("C:/Temp2/targetFile.jpg"); long start = System.nanoTime(); while (true) { int data = fis.read(); if (data == -1) break; fos.write(data); } System.out.println("기본 파일스트림 걸린 시간: " + (System.nanoTime() - start)); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); start = System.nanoTime(); while (true) { int data = fis.read(); if (data == -1) break; bos.write(data); } System.out.println("버퍼 보조 스트림 걸린 시간: " + (System.nanoTime() - start)); bis.close(); bos.flush(); bos.close(); fis.close(); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }
 

핵심 키워드

  • 프로그램이 입출력 소스와 직접 작업하지 않고 중간에 메모리 버퍼와 작업함으로서 실행 성능을 향상시킬 수 있다.
 

DataIOStreamExam.java

package ch18; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; public class DataIOStreamExam { public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream("C:/Temp2/test3.txt"); DataOutputStream dos = new DataOutputStream(fos); dos.writeUTF("홍길동"); dos.writeDouble(95.5); dos.writeInt(1); dos.writeUTF("김자바"); dos.writeDouble(90.5); dos.writeInt(2); dos.close(); fos.close(); FileInputStream fis = new FileInputStream("C:/Temp2/test3.txt"); DataInputStream dis = new DataInputStream(fis); for (int i = 0; i < 2; i++) { String name = dis.readUTF(); double score = dis.readDouble(); int num = dis.readInt(); System.out.println(name + " " + score + " " + num); } fis.close(); dis.close(); } catch (Exception e) { e.printStackTrace(); } } }
 

핵심 키워드

  • 바이트 스트림에 DataInputStream과 DataOutputStream 보조 스트림을 연결하면 기본 타입인 boolean, char, short, int, long, float, double 값을 입출력할 수 있다.
  • 이 경우 주의할 점으로 데이터 타입의 크기가 모두 다르므로 DataOutputStream으로 출력한 데이터를 다시 DataInputStream으로 읽어 올 때에는 출력한 순서와 동일한 순서로 읽어야 한다는 것이다.
 

PrintStreamExam.java

package ch18; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamExam { public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream("C:/Temp2/print.txt"); PrintStream ps = new PrintStream(fos); ps.print("마치 "); //소스는 System.out과 같고 출력이 되는 경로만 콘솔에서 파일로 바꼈다. ps.println("프린터가 출력하는 것처럼 "); ps.println("데이터를 출력합니다. "); ps.printf("| %6d | %-10s | %10s | \n", 1, "홍길동", "도적"); ps.printf("| %6d | %-10s | %10s | \n", 2, "김자바", "학생"); } catch (Exception e) { e.printStackTrace(); } } }
 

핵심 키워드

  • PrintStream과 PrintWriter는 프린터와 유사하게 출력하는 print(), println(), printf() 메소드를 가지고 있는 보조 스트림이다.
  • PrintStream은 바이트 출력 스트림과 연결되고, PrintWriter는 문자 출력 스트림과 연결된다.
 

Member.java

package ch18; import java.io.Serializable; public class Member implements Serializable{ //직렬화가 가능하다고 명시하는 역할. /** * */ private static final long serialVersionUID = -1616065040391964919L; //랜덤 키값 주어짐 private String id; private String name; public Member(String id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "Member [id=" + id + ", name=" + name + "]"; } }

Product.java

package ch18; import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.ToString; @AllArgsConstructor @ToString public class Product implements Serializable{ /** * */ private static final long serialVersionUID = 7394135165810371117L; private static String company = "삼성"; //생성자에 정적 필드는 포함 안됨 private String name; private int price; private transient int pid; //직렬화에서 뺴주는 키워드 (예외 라는 뜻). 런타임 중에서만 확인 가능 }

ObjectIOStreamExam.java

package ch18; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Arrays; public class ObjectIOStreamExam { public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream("C:/Temp2/object.dat"); ObjectOutputStream oos = new ObjectOutputStream(fos); Member m1 = new Member("spring", "봄"); Product p1 = new Product("노트북", 1500000, 1); int[] arr = { 1, 2, 3 }; //직렬화 oos.writeObject(m1); oos.writeObject(p1); oos.writeObject(arr); fos.close(); oos.close(); FileInputStream fis = new FileInputStream("C:/Temp2/object.dat"); ObjectInputStream ois = new ObjectInputStream(fis); //역직렬화 Member m2 = (Member) ois.readObject(); //object로 반환하지만 내용물은 member니깐 강제 형변환해도 문제 x Product p2 = (Product) ois.readObject(); int[] arr2 = (int[]) ois.readObject(); fis.close(); ois.close(); System.out.println(m2); System.out.println(p2); System.out.println(Arrays.toString(arr2)); } catch (Exception e) { e.printStackTrace(); } } }
 

핵심 키워드

  • 자바는 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수 있다. 객체를 출력하려면 필드값을 일렬로 늘어선 바이트로 변경해야 하는데, 이것을 직렬화라고 한다. 반대로 직렬화된 바이트를 객체의 필드값으로 복원하는 것을 역직렬화라고 한다.
  • ObjectOutputStream은 바이트 출력 스트림과 연결되어 객체를 직렬화하고, ObjectInputStream은 바이트 입력 스트림과 연결되어 객체로 복원하는 역직렬화를 한다.
  • 자바는 Serializable 인터페이스를 구현한 클래스만 직렬화를 할 수 있도록 제한한다.
  • transient 키워드를 필드에 사용하면 직렬화에 포함이 되지 않는다.
 

FileExam.java

package ch18; import java.io.File; import java.io.IOException; public class FileExam { public static void main(String[] args) throws Exception { File dir = new File("C:/Temp2/images"); File file = new File("C:/Temp3/images/img.jpg"); // if (!dir.exists()) // dir.mkdir(); // // if (!file.exists()) // file.mkdirs(); file.createNewFile(); // file.delete(); if(file.isDirectory()) { System.out.println("디렉토리 입니다."); } if(file.isFile()) { System.out.println("파일 입니다."); } } }
 

핵심 키워드

  • File 클래스의 .exist()메소드를 통해 false를 리턴받을 경우, createNewFile(), mkdir(), mkdirs()메소드를 통해 파일 또는 폴더를 생성할 수 있다.
  • File 클래스의 .exist()메소드를 통해 true를 리턴받을 경우, delete(), canExecute(), canRead(), canWrite(), getName(), getParent(), getParentFile(), getPath(), isDirectory(), isFile(), isHidden(), lastModified() 등의 메소드를 사용할 수 있다.
 

FilesExam.java

package ch18; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class FilesExam { public static void main(String[] args) throws Exception { String data = """ id: winter email: winter@mycompany.com tel: 010-1234-5678 """; Path path = Paths.get("C:/Temp2/user.txt"); Files.writeString(path, data, Charset.forName("UTF-8")); System.out.println(Files.probeContentType(path)); System.out.println(Files.size(path)); System.out.println(Files.readString(path, Charset.forName("UTF-8"))); } }
 

핵심 키워드

  • Files 클래스는 정적 메소드로 구성되어 있기 때문에 File 클래스처럼 객체로 만들 필요가 없다. Files의 정적 메소드는 운영체제의 파일 시스템에게 파일 작업을 수행하도록 위임한다.
 

결론

해당 문제를 풀면서 자바에서 데이터 입출력에 필요한 스트림을 활용하는 방법을 익힐 수 있었다.
 
Share article

More articles

See more posts

👨🏻‍💻DriedPollack's Blog