파일 입출력
간단하게 파일 폴더 생성하고 정보확인
java.io.File 클래스를 이용
파일/폴더 경로를 표현하는 객체
상대경로 : 지금 내 위치를 기반으로 다른 경로를 탐색
절대경로 : 윈도우 기준으로 C:~ D:~, Unix기준으로 /root/~ 최상위 루트를 기준을 다른 경로를 탐색
public static void main(String[] args) {
//1. 경로지정없이 파일객체를 생성(상대경로 - 현재 작업 폴더 기준)
File f1 = new File("test.txt");
//파일 객체를 하나 생성(실제파일X -> 코드로 존재하는 파일 객체)
//2. 실제 존재하는 경로에 파일 생성(절대경로)
File f2 = new File("D:\\test.txt");
//3. 존재하지 않는 경로에 파일 생성
File f3 = new File("D:\\tmp\\test.txt");
try {
f1.createNewFile(); //createNewFile() 시점에 실제 파일이 만들어 짐.
f2.createNewFile();
//f3.createNewFile(); 존재하지 않는 경로로 생성시 예외발생 -> IOException
//폴더를 먼저 생성하고 파일을 만들면 됨
File tmpFolder = new File("D:\\\\tmp");
tmpFolder.mkdir();
f3.createNewFile();
//파일정보 가져오기
File f4 = new File("ttt.txt");
//exists() 파일 존재 유무 확인
System.out.println("exists : "+ f4.exists());
System.out.println("exists : "+ f1.exists());
//isFile() 파일 유무 확인
System.out.println("isFile : " + f1.isFile());
System.out.println("isFile : " + tmpFolder.isFile());
System.out.println("파일명 : " + f1.getName());
System.out.println("파일경로 : " + f1.getAbsolutePath());
System.out.println("파일용량 : " + f1.length());
System.out.println("파일상위폴더 : " + f1.getParent());
} catch (IOException e) {
e.printStackTrace();
}
}
자바 스트림
프로그램가 외부매체(파일, 네트워크, 콘솔...) 간의 데이터 전달 통로
데이터를 순차적으로 흘려보내는 파이프같은 구조
스트림의 특징
- 단방향 : 입력이면 입력만, 출력이면 출력만 가능 -> 동시에 원하면 각각 만들어줘야한다.
- 순차적으로 처리(FIFO) : 먼저 보낸 데이터가 먼저 나온다.
- 시간 지연 가능성 : 외부매체와 연결되므로 입출력속도가 상대적으로 느릴 수 있음.
스트림의 구분
데이터 단위에 따른 구분(바이트스트림(1Byte), 문자스트림(2Byte))
- 바이트스트림(InputStream, OutputStream) : 이미지, 동영상, 바이너리 데이터 등...
- 문자스트림(Reader, Writer) : 텍스트 데이터(문자/문자열)...
외부 매체 연결 방식에 따른 구분
- 기반스트림 : 외부 매체와 직접연결되는 스트림(필수, 단독 사용가능)
- 보조스트림 : 기반스트림 감싸서 성능 향상이나 기능추가 제공(단독사용불가, 반드시 기반스트림과 함께 사용)
프로그램에서 파일(출력)
public void fileSave() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("1_buffer.txt"));){
/*
//1. 기반스트림 생성
FileWriter fw = new FileWriter("1_buffer.txt");
//2. 보조스트림 생성시 기반스트림 객체를 전달하여 새성
BufferedWriter bw = new BufferedWriter(fw);
fw.close();
*/ //-> 위에 작성한 try()와 주석처리는 같다.
bw.write("안녕하세요");
bw.write("안녕하세요");
bw.newLine();
bw.write("안녕하세요");
bw.flush(); //버퍼 강제 비움
} catch (IOException e) {
e.printStackTrace();
}
}
1_buffer.txt가 없으면 파일을 만들고 있으면 만들지 않는다.
bw객체로 write메서드를 사용하여 파일에 작성하고
flush로 남은 데이터들을 비운다.
public void fileSaveWithStream() {
FileOutputStream fo = null;
try{
//1. 기반스트림 생성
fo = new FileOutputStream("1_buffer.txt");
//2. 기반 스트림 -> OutputStream을 writer로 사용할 수 있게 보조
OutputStreamWriter osw = new OutputStreamWriter(fo, "UTF-8");
//3. 보조스트림 생성시 기반스트림 객체를 전달하여 생성
BufferedWriter bw = new BufferedWriter(osw);
bw.write("안녕하세요\n");
bw.write("안녕하세요");
bw.newLine();
bw.write("안녕하세요");
bw.flush(); //버퍼 강제 비움
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
외부매체(파일) -> 프로그램(입력)
public void fileRead() {
try (BufferedReader br = new BufferedReader(new FileReader("1_buffer.txt"));){
/*
System.out.println(br.readLine());
System.out.println(br.readLine()); 파일에 모든 내용을 읽은 후에는 null반환
*/
String text = null;
while((text = br.readLine()) != null) {
System.out.println(text);
}
}catch (IOException e){
e.printStackTrace();
}
}
FileReader : 파일을 직접적으로 연결해서 2바이트 단위로 입력받을 수 있는 기반스트림
BufferedReader : 한줄씩 읽어오는 기능이 가능한 보조스트림
직열화와 역직열화
직열화
객체는 메모리안에서 존재하는 인스턴스 개념이기 때문에 그대로 전송할 수 없음, 직열화 후 이진데이터로 외부에 전송 가능.
객체(object)를 바이트 형태로 변환하는 과정
파일에 저장하거나 네트워크로 전송할 수 있도록 함
자바에서는 클래스를 직열화하기위해 직열화 대상 클래스에게는 implements Serializable 해야한다.
역직열화
저장해 두거나 전송했던 데이터를 다시 원래 객체처럼 사용하기 위해 역직렬화 진행
저장된 바이트 데이터를 다시 객체로 복원하는 과정
프로그램 -> 파일(출력) : 객체(직열화)
public void objectSave() {
Product p1 = new Product("아이폰16", 1200000);
Product p2 = new Product("아이폰16pro", 1400000);
Product p3 = new Product("아이폰16mini", 1000000);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("product1.dat"));){
oos.writeObject(p1); //직렬화 후 파일에 객체를 저장
oos.writeObject(p2);
oos.writeObject(p3);
} catch (IOException e) {
e.printStackTrace();
}
}
열어보면 저장되어 있지만, 사람이 읽을 수 없는 문자들이 저장되어 있다.
파일 -> 프로그램(입력) : 객체바이트코드(역직렬화)
public void objectRead() {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("product1.dat"));){
Object obj = ois.readObject();
if (obj instanceof Product) {
Product p1 = (Product)obj; //Object이기에 다운캐스팅
System.out.println(p1);
}
} catch (IOException e) {
System.out.println("객체 읽기 중 에러 발생");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("직렬화 대상을 찾을 수 없습니다.");
e.printStackTrace();
}
}
public class Product implements Serializable{
private String name;
private int price;
public Product() {
super();
}
public Product(String name, int price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Product [name=" + name + ", price=" + price + "]";
}
}
JAVA API
API는 프로그램을 만들 때 사용할 수 있도록 제공되는 미리 만들어진 기능의 모음.
-> 미리 작성해 둔 유용한 인터페이스(명령어, 클래스, 메서드, 라이브러리 등)
자바 API(자바 표준 라이브러리)
자바언어는 기본 문법(변수, 제어문, 클래스 등...)만 제공
실제 개발할 때는 문자열 처리, 날짜 계산, 입출력, 네트워크 통신, 자료구조 상용 등 수많은 기능이 필요
이런 기능을 자바 개발팀에서 미리 구현해 둔 클래스/인터페이스 집합을 JAVA 표준 API
ex) java.lang.String, java.io.File 등...
String
public void method01() {
//1. 생성자를 통한 문자열 생성
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1);
System.out.println(str2.toString());
//String클래스에 toString메서드는 이미 오버라이딩 되어 있음
//그래서 참조 변수 출력시 Object의 toString형식(타입@주소값16진수)이 아니라 String의 저장된 문자열이 반환
System.out.println(str1 == str2);
//String객체의 주소값을 비교하기 때문에 false가 나옴
System.out.println(str1.equals(str2));
//String클래스에서 equals메서드도 이미 오버라이딩 되어있음(주소값비교가 아니라 문자열 값을 비교하도록)
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
//String클래스에서 hashcode메서드도 이미 오버라이딩 되어있음(주소값이 아닌 문자열을 가지고 해시값을 비교하도록)
//System.identityHashCode(참조변수)
//해당 참조변수의 메모리값을 기반으로한 해시값을 반환
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
System.out.println("---------------------------------------------------------------");
//2. 문자열을 리터럴값으로 생성
String str3 = "Hello";
String str4 = "Hello";
System.out.println(str3 == str4);
//문자열 리터럴을 사용시 상수풀영역에 문자열을 생성한다.
//String pool : 동일한 문자열을 중복해서 가지지 않는다.
System.out.println(str3.hashCode());
System.out.println(str4.hashCode());
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
System.out.println(System.identityHashCode(str3));
System.out.println(System.identityHashCode(str4));
str3 = "Bye";
System.out.println(System.identityHashCode(str3));
System.out.println(System.identityHashCode(str4));
//String 리터럴의 특성상 참조변수의 값을 변경하는 순간, 기존의 문자열 메모리의 값을 변경하는 것이 아니라
//상수이기 때문에 새로운 값을 String pool에 만들고 참조하도록 되어 있음.
}
String은 Object에 있는 toString()을 오버라이딩을 하고 오버라이딩한 toString()은 저장한 String값을 반환하는 메서드이다
Wrapper클래스
기본자료형을 객체로 포장해 줄 수 있는 클래스
boolean(Boolean)
char(Char)
byte(Byte)
...
원시타입을 객체로 표현해야 할 경우 사용
- 메서드의 매개변수로 전달해야할 때
- 원시타입에도 다형성을 적용하고 싶을 때
public class WrapperAPI {
public void method() {
//Boxing : 기본자료형 -> Wrapper클래스 자료형
int num1 = 10;
int num2 = 20;
System.out.println(num1 == num2);
//1. 객체 생성구문 통해서 클래스 타입으로 변경
Integer i1 = new Integer(num1);
//2. 객체를 생성하지 않고 곧바로 대입(AutoBoxing)
Integer i2 = num2; // new Integer(num1);
System.out.println(i1.equals(i2));
System.out.println(i1.equals(10));
System.out.println(i1.compareTo(i2));
//두 값을 비교해서 기준값이 크면 1, 전달값이 크면 -1, 동일하면 0 반환
//문자욜을 Integer 타입으로 변환하고 싶을 때 -> 객체생성을 통해서 가능
Integer i3 = Integer.parseInt("13");
Integer i4 = new Integer("13");
//Unboxing : Wrapper클래스 자료형 -> 기본자료형
//1. Wrapper클래스에서 제공하는 xxxValue() 메서드 사용
int num3 = i3.intValue();
//2. 메서드 사용하지 않고 바로대입(AutoUnboxing)
int num4 = i4;
//int뿐만이 아니라 다른 자료형도 가능
}
}