// 복사될 파일 경로명을 설정하는 예제public class Test { public static void main(String[] args) { String s = "C:/Users/owner/youngRepositories/SSangYoung/dev/temp/java_read.txt"; StringBuilder sb = new StringBuilder(s); // 파일명에 '.'이 여러개 나올 수 있으므로 파일 확장자는 마지막 .뒤에 문자열이다. // 따라서 lastIndexOf를 사용해서 확장자를 잘라내야 함. // StringBuilder에 삽입하는 insert method로 .있는 부분부터 "_bak"을 추가함 System.out.println(sb.insert(s.lastIndexOf("."),"_bak")); }}
FileInputStream, FileOutputStream으로 파일 복사 구현
hdd에서 데이터를 읽을때 access arm이 움직여 헤드로 데이터를 읽음
read 메서드는 헤드가 얼마나 많이 읽을 수 있는지와는 상관없이 1byte씩 읽어온다.
오버로드된 read 메서드를 보면 파라미터로 byte배열을 주면 한번에 배열의 크기만큼 읽어들일 수 있음
byte[] b = new byte[512];int len = 0;// 읽어들일 때 byte배열의 크기만큼 데이터가 없을 수 있다.len = fis.read(b); // int로 읽어들인 byte의 수를 반환
// byte배열의 크기만큼 데이터가 존재하지 않을 수 있기 때문에 읽어들인 길이만큼만 출력while(len = fis.read(b) != -1) { fos.write(b, 0, len); // 0번부터 len까지 출력}
// 파일복사 예제@SuppressWarnings("serial")public class FileCopy extends JFrame implements ActionListener { private JButton jb; private JProgressBar jpb; public FileCopy() { super("파일 복사"); jb = new JButton("파일 선택"); jpb = new JProgressBar(0, 100); jpb.setString("진척도"); jpb.setStringPainted(true); jpb.setValue(50); JPanel jp = new JPanel(); jp.add(jb); add("Center",jp); add("South",jpb); jb.addActionListener(this); setBounds(100, 100, 500, 200); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent e) { FileDialog fd = new FileDialog(this, "선택", FileDialog.LOAD); fd.setVisible(true); String path = fd.getDirectory(); String name = fd.getFile(); if (path != null) { // 파일 선택시 File file = new File(path+name); try { copy(file); JOptionPane.showMessageDialog(this, file+" 복사 성공."); } catch (FileNotFoundException fnfe) { JOptionPane.showMessageDialog(this, "파일이 존재하지 않습니다."); fnfe.printStackTrace(); } catch (IOException ie) { JOptionPane.showMessageDialog(this, "입출력 작업에 문제가 발생."); ie.printStackTrace(); } } } public void copy(File file) throws FileNotFoundException, IOException { int selectValue = JOptionPane.showConfirmDialog(this, "파일을 복사하시겠습니까?"); switch(selectValue) { case JOptionPane.OK_OPTION : StringBuilder copyFileName = new StringBuilder(file.getAbsolutePath()); copyFileName.insert(copyFileName.lastIndexOf("."), "_bak"); FileInputStream fis = null; FileOutputStream fos = null; try { // 원본 파일에 스트림 연결 fis = new FileInputStream(file); fos = new FileOutputStream(copyFileName.toString()); // 파일과 연결된 스트림에서 값을 얻는다. // HDD가 읽어들이는 크기를 무시하고 1byte씩 읽어들여 사용 int temp = 0; long fileLen = file.length(); int i = 0; while( (temp = fis.read()) != -1 ) { // 읽어 들인 내용을 _bak가 붙은 파일을 생성하여 출력(복사) fos.write(temp); fos.flush(); jpb.setValue((int)(i/(double)fileLen*100)); // Thread를 사용해야 프로그레스바 구현가능, 여기선 값만 찍음 System.out.println(jpb.getValue()); i++; } /*// HDD가 읽어들이는 크기를 그대로 사용 byte[] temp = new byte[512]; int len = 0; while ((len = fis.read(temp)) != -1) { fos.write(temp,0,len); fos.flush(); }*/ } finally { if (fis != null) fis.close(); if (fos != null) fos.close(); } } } public static void main(String[] args) { new FileCopy(); }}
ObjectStream
객체(instance)는 Stream을 타고 JVM 밖으로 나갈 수 없다.
객체의 주소는 4byte이기는 하나 객체 자체의 크기를 알 수 없기 때문에 쪼갤 수 없다.
기본형 데이터형은 Stream을 타고 JVM 밖으로 나갈 수 있다.
크기를 알 수 있기 때문에 쪼개져서 나갈 수 있다.
8bit Stream
ObjectInputStream
JVM 외부 객체를 읽기
ObjectOutputStream
JVM 외부에 객체를 내보내기
객체가 **직렬화(Serialization)**되면 JVM 외부로 나갈 수 있다.
객체는 Serializable이란 인터페이스를 구현하면 직렬화 될 수 있다.
직렬화된 객체는 instanceof를 사용해서 판별
FileOutputStream fos = new FileOutputStream(파일객체);ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(직렬화가된객체); // 스트림에 객체를 기록oos.flush(); // 목적지로 분출
직렬화를 방지하려면 변수앞에 접근지정자로 transient를 붙이면 그 변수는 JVM 외부로 나갈 수 없게된다.
transient String s; //
파일을 읽어와 객체로 다시 만들어 사용하는 것이 Unmarshaling
FileInputStream fis = new FileInputStream("파일명");ObjectInputStream ois = new ObjectInputStream(fis);B b = (B)ois.readObject();
// 데이터를 가지고 있는 클래스로 직렬화 대상 클래스public class UserData implements Serializable { private int age; private double weight; private String name; public UserData() { } public UserData(int age, double weight, String name) { super(); this.age = age; this.weight = weight; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "UserData [age=" + age + ", weight=" + weight + ", name=" + name + "]"; }}
// UserData를 객체로 생성, 출력스트림을 통해 파일로 내보내고 읽어들이기public class UseObjectStream { public void useObjectOutputStream() throws IOException { ObjectOutputStream oos = null; try { File file = new File("C:/Users/owner/youngRepositories/SSangYoung/dev/temp/obj_data.dat"); // 객체(JVM)를 직렬화하여 목적지 (HDD File)로 내보내는 스트림 oos = new ObjectOutputStream(new FileOutputStream(file)); // 객체는 직렬화가 되지 않으면 스트림으로 내보낼 수 없다. UserData ud = new UserData(26,70.1,"이재현"); oos.writeObject(ud); // 객체를 직렬화하여 스트림에 쓴다. oos.flush(); // 스트림에 기록된 내용을 목적지로 분출한다. System.out.println("객체를 파일로 기록!"); } finally { if (oos != null) { oos.close(); } } } public void useObjectInputStream() throws IOException, ClassNotFoundException { // 객체를 읽기위한 스트림 열기 ObjectInputStream ois = null; try { File file = new File("C:/Users/owner/youngRepositories/SSangYoung/dev/temp/obj_data.dat"); ois = new ObjectInputStream(new FileInputStream(file)); UserData ud = (UserData)ois.readObject(); System.out.println(ud.toString()); } finally { if (ois != null) ois.close(); } } public static void main(String[] args) { UseObjectStream uos = new UseObjectStream(); try { uos.useObjectOutputStream(); } catch (IOException ie) { ie.printStackTrace(); } System.out.println("================================================="); try { uos.useObjectInputStream(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
// transient로 직렬화를 막기public class UserData implements Serializable { private int age; private transient double weight; private transient String name;
serialVersionUID
JVM 밖으로 내보내고 들어오는 instance는 코드의 변형 또는 가공이 될 수 있기 때문에 내보냈던 코드를 검증하기 위해 serialVersionUID를 사용
serialVersionUID는 클래스의 hashcode로 사용
대표적인 예가 공인인증서
serialVersionUID 추가 후 파일 내보내고 serialVersionUID값변경 후 다시 읽어들이려고하면 에러발생
// 클래스 객체를 JVM 밖으로 내보낸다면 serial Version ID를 생성해준다.// 클래스를 안내보낸다면 SuppressWarning처리를 해주면 됨@SuppressWarnings("serial")public class UserData implements Serializable {
실행가능한 jar파일 만들기
프로젝트 선택 - Export - Runnable JAR File Export
Launch configuration : main method가진 클래스 선택
Export destination : 파일을 내보낼 위치, 파일명 지정
실행을 위해 bat파일 생성
java_memo_env.bat (기존 env.bat 복사)
java_memo_run.bat (기존 eclipse.bat 복사)
# java_memo_envrem path - 특정프로그램(javac.exe, java.exe)를 설치된 경로에 상관없이 사용하기위한 pathrem xxx_home - 프로그램끼리 경로를 참조하기 위해 설정하는 pathset dev_home=C:\Users\owner\youngRepositories\SSangYoung\devset java_home=%dev_home%\Java\jdk1.8.0_191set path=%java_home%\bin;