- 1011 (18일차)2023년 10월 11일 16시 31분 10초에 업로드 된 글입니다.작성자: 삶은고구마
scanner로 입력받을때의 nextInt()의 상위클래스를 확인하면 여기서도 throw를 사용한다.
입출력(IO)
JVM 기준
데이터가 들어오면 입력(scanner), 나가면 출력(print).
node : 기본 (대상과 연결됨 필수,성능이 좀 떨어짐) / filter : 보조 ※바이트/ 문자 기반 마다 정해진 입출력 클래스가 있기 때문에 교차해서 사용할 수 없다.
nodeStream이 필수인 이유:
시스템 입출력과 직접 연결됨.
보조스트림은 그런 필수 스트림을 감싸서 사용함.
-표준 입출력
-System.in : 표준입력 (사용자 키보드 입력)
-System:out : 표준출력 (콘솔 출력)
-System.err : 표준에러
Scanner가 나오기 전 까진 아래의 방법으로 입력을 받았다.
-1은 더 이상 읽어올 값이 없을때 반환되는 값.
try { while((input = System.in.read())!=-1) { System.out.println(input); /** * a * 97 (알파벳 a) * 13 \r (맨 앞으로 가라) * 10 \n (개행) * 13과 10은 엔터를 치면서 발생. * 아스키코드표 참고 */ } } catch (IOException e) { e.printStackTrace(); }
-입출력 스트림
표준 입출력을 제외한 모든 stream 클래스는 사용 후
close() 통해 자원을 반납해야 한다. os내에서 사용되는 메모리라서 사용이 끝났으면 반환.
상대적 경로 절대적 경로 기준 현재 디렉토리 기준
(프로젝트 root directory)루트 디렉토리 기준
윈도우: C:\~
맥: /~디렉토리 명에 한글/공백이 있으면 오류가 발생한다. byte 예제 코드1
더보기private void test1() { FileInputStream fis=null; FileOutputStream fos = null; try { // fis = new FileInputStream("abc/abc.txt");//생성 // fos = new FileOutputStream("abc/abc_copy.txt",true);//뒤에 t,f는 이어붙이기 여부 확인 생략시 false fis = new FileInputStream("abc/abc.txt");//생성 //이스케이핑 처리 //fos = new FileOutputStream("C:\\Users\\user1\\Desktop\\abc_copy2.txt",true); fos = new FileOutputStream("C:/Users/user1/Desktop/abc_copy3.txt",true); //이어쓰기는 객체입출력에선 불가 int data = 0; while((data=fis.read())!=-1) { System.out.println(data); /** * 영문과 숫자 등은 1byte씩 처리되어서 온전히 출력되지만.. * 한글과 한자는 3byte가 합쳐져서 한글자가 되는거라(utf-8) * 1byte씩 읽어오면 아마 깨질것 */ fos.write(data); } } catch (IOException e) //FileNotFondException(자식)도 핸들링. 부모클래스라서. //하지만 NullFoninterException은 잡을수 없어서 Exception으로 해도됨 { e.printStackTrace(); } finally { try { fis.close();//try안에서 선언된 변수라 접근 못함..try위에서 선언. } catch (Exception e) { e.printStackTrace(); } try { fos.close(); //fis.close(); 밑에 적으면 좋겠지만..예외는 따로 처리하는것이 좋다. //fis.close()에서 예외처리 당하면 아랫줄은 skip되기 때문임. } catch (Exception e) //IOException에서 Exception으로 바꾸는 이유. //fos=null인상태에서 예외처리 하기 위함.io면 nullpointEx 감지 못함 { // TODO Auto-generated catch block e.printStackTrace(); } } }
byte 말고 byte 배열로도 입출력 작업이 가능하다.
byte[] 예제 코드2
더보기/** * test2 개선 * -read():int * -read(byte[]):int * -try..with..resource(jdk 1.7) - Stream 객체의 선언과 반납 처리 (finally 불필요) */ private void test3() { try (//대입x 선언 FileInputStream fis = new FileInputStream("C:\\Users\\user1\\Desktop\\image\\nongdam.jpeg"); FileOutputStream fos = new FileOutputStream("nongdam_copy.jpeg"); ){ byte[] buf = new byte[8192]; //기본:8kb 다른 수치로도 가능. int len = 0; //read(byte[])의 반환값은 읽어낸 byte 갯수 while((len=fis.read(buf))!=-1) //읽어올 값이 없으면 -1리턴 { System.out.println(len); fos.write(buf,0,len); //buf의 idnex 0번부터 읽어낸 길이만큼 써라. } } catch (IOException e) { e.printStackTrace(); } }
보조 스트림
1.기본 스트림의 성능향상 또는 부가기능을 위해 n개를 추가해서 쓸 수있다.
2.반드시 기본 스트림이 필요함(표준 입출력과 직접 연결됨)
보조 스트림 단독 사용 불가
3.기본스트림 객체를 감싼 구조. 보조스트림 객체만 제어하면 된다.
4.보조스트림 객체만 반환하면 기본 스트림까지 반환된다.
주의 사항: 입력-입력끼리, 문자기반-문자기반 끼리 사용 가능. 교차사용 불가
보조스트림 예제 코드
더보기private void test4() { String srcName = "C:\\Users\\user1\\Desktop\\image\\nongdam.jpeg"; String destName = "nongdam_copy.jpeg"; try ( //기본스트림이 인자로 반드시 있어야함 //기본스트림=대상과 직접 연결 //보조스트림=기본에 성능만 추가 srcName과 직접 연결 불가 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcName)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(srcName)); ){ byte[] buf = new byte[8192]; //기본:8kb int len = 0; //read(byte[])의 반환값은 읽어낸 byte 갯수 //보조스트림 bis ,bos 만 사용 while((len=bis.read(buf))!=-1) { System.out.println(len); bos.write(buf,0,len); } } catch (IOException e) { e.printStackTrace(); } }
문자 기반 스트림
한 글자 씩 처리한다.(한글 깨짐 없음) 텍스트 파일을 처리할 때 사용.
FileReader 문자기반 입력 스트림
FileWriter 문자기반 출력 스트림
예제 코드1
더보기//문자 단위로 작업 private void test1() { //파일 객체를 만들어서 reader에 인자로 사용해도 됨 //실제,가상의 파일을 가리키는 자바 객체 (파일 자체는 아님) //file 객체를 통해서 실제 파일을 제어하는 것이 가능함. //스트림도 파일 사용가능 File src = new File("abc/abc.txt"); File dest = new File("abc/abc_copy3.txt"); try(//finally x FileReader fr = new FileReader(src); FileWriter fw = new FileWriter(dest); ){ int data = 0; while((data = fr.read())!=-1) { System.out.print((char)data); fw.write(data); } } catch (IOException e) { e.printStackTrace(); } }
예제 코드1의 보조스트림 버전 코드
더보기/** * test1의 보조스트림 버전 * 입력스트림:읽어올 파일이 없으면 오류.(반드시 존재!!) * 출력스트림:출력할 파일이 없어도 오류안남. 없으면 스트림클래스에서 새로 생성 */ private void test2() { File src = new File("abc/abc.txt"); File dest = new File("abc/abc_copy4.txt"); //디렉토리는 반드시 존재 해야함... //경로없을 시:FileNotFoundException:abcz\abc_copy4.txt (지정된 경로를 찾을 수 없습니다) try( BufferedReader br = new BufferedReader(new FileReader(src)); BufferedWriter bw = new BufferedWriter(new FileWriter(dest)); ) { String data =null; /** * readLine():개행문자까지 읽어서 개행문자를 버리고 반환 */ while((data=br.readLine())!=null) //readLine:한줄씩 { System.out.print(data); bw.write(data+"\n"); //개행추가해야 원본과 동일 } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
브릿지 예제 코드
더보기/** * jdk1.5에 추가된 Scanner 이 전의 사용자 입력값.. * -System.in - BufferedReader * (byte - String 사이 브릿지 역할:inputStreamReader) */ private void test3() { try { //스캐너와 다르게 예외처리 필수.. //System.in:표준입력이 있어서 close()하지 않음. //브릿지 //표준입출력 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("아무말:"); String str = br.readLine(); //sc.next() 처럼.. System.out.printf("\"%s\"라고 하셨습니다.",str); } catch(Exception e) { e.printStackTrace(); } }
-파일
java.io.File
1.실제 / 가상의 파일 , 디렉토리를 가리키는 자바 객체
2.파일 생성,삭제,메타정보 조회..
3.디렉토리 생성, 삭제, 자식 파일 조회 등등 쓰임새가 다양하다.
파일 객체 생성 File f = new File(경로); 파일명 f.getName() 경로(파일명 제외) f.getParent() 절대 경로 f.getAbsolutePath() 존재 유무
(boolean)f.exists() 파일인가?
(boolean)f.isFile() 디렉토리인가?
(boolean)f.isDirectory() 파일명 변경(이동) File f2 = new File(새 경로);
f.renameTo(f2);파일 삭제 f.delete() 새 디렉토리 만들기
단일dir.mkdir(); 새 디렉토리 만들기
복수dir.mkdirs(); 파일 예제 코드1
더보기private void test1() { File f = new File("abc/abc.txt"); //상대경로 System.out.println(f);//toString override File f2 = new File("C:\\Workspaces\\java_workspace\\14_IO\\abc\\abc.txt"); //절대경로 System.out.println(f2); System.out.println(f2.getName()); //파일명만 보여줌 System.out.println(f2.getParent()); //경로(파일명뺀) System.out.println(f.getAbsolutePath());//절대경로 System.out.println(f.exists());//존재:true System.out.println(f.isFile()); System.out.println(f.isDirectory()); File f3 = new File("abc/def.txt"); if(!f3.exists()) { System.out.println(f3+"을 생성합니다."); try { f3.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //파일명 변경 = 이동 File dest = new File("def.txt"); f3.renameTo(dest); //f3.delete();//파일삭제도 있다. }
파일 예제 코드2
사용자 입력값을 받아 폴더와 txt파일 만들기
더보기/** * 사용자 이름을 입력받아 members 하위에 사용자명/사용자명.txt 파일을 생성. * -members/홍길동/홍길동.txt * -members,사용자명 디렉토리를 동적으로 생성. */ private void test3() { Scanner sc = new Scanner(System.in); System.out.print("사용자 명을 입력하세요. : "); String userStr = sc.next(); File dir = new File("C:\\Workspaces\\java_workspace\\14_IO");//절대경로 File newDir = new File("members"); if(!newDir.exists()) //존재하지 않는다면 { newDir.mkdir(); System.out.println(newDir+"생성완료"); } File newDir2 = new File(newDir+"/"+userStr); //or (newDir,파일명); if(!newDir2.exists()) //존재하지 않는다면 { newDir2.mkdir(); System.out.println(newDir2+"생성완료"); } File myFile = new File("members/"+userStr+"/"+userStr+".txt"); if(!myFile.exists()) { try { myFile.createNewFile(); System.out.println(myFile+"을 생성합니다."); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-오브젝트 입출력
객체 단위로 읽고/쓰기를 지원하는 스트림(byte 기반)
1)ObjectInputStream
2)ObjectOutputStream
읽기/쓰기를 작업할 클래스는 반드시 serializable 인터페이스를 구현해야 한다.
serializable란?
추상 메소드가 없는 마커 인터페이스..(추후 따로 공부하기)
객체를 하나만 읽고 쓸 수도, 여러개를(리스트) 읽고 쓸 수 있다.
오브젝트 입출력 예제 코드 1
객체 하나만
더보기/** * -객체 하나 쓰기 읽기 */ private void test1() { // TODO Auto-generated method stub try( ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser")); ) { oos.writeObject(new User("honggd","1234",LocalDateTime.now())); System.out.println("저장 완료!"); //NotSerializableException } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) { User user = (User)ois.readObject(); System.out.println(user); } catch (IOException | ClassNotFoundException e) { //멀티 캐치 : 부모자식간 사용 불가 // TODO: handle exception e.printStackTrace(); } }
오브젝트 입출력 예제 코드 2
리스트를 사용하여 여러개를 다룬다.
더보기/** * -객체 List에 담아 입출력. */ private void test2() { List<User> users = new ArrayList<>(); users.add(new User("honggd","1234",LocalDateTime.of(2023,10,10, 10, 10))); users.add(new User("sinsa","1234",LocalDateTime.of(2023,10,9, 9, 9))); users.add(new User("leess","1234",LocalDateTime.of(2023,10,8, 8, 8))); //ObjectOutputStream - BufferedOutputStream - FileOutputStream try ( ObjectOutputStream oos = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("users.ser"))); ) { oos.writeObject(users); System.out.println("저장 완료..."); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
출력.
/** * ObjectInputStream - BufferedInputStream - FileInputStream */ private void test3() { try( ObjectInputStream ois = new ObjectInputStream( new BufferedInputStream( new FileInputStream("users.ser"))); ) { List<User>users = (List<User>)ois.readObject(); System.out.println(users); } catch (IOException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
객체 입출력 시 사용한 User 클래스.
상단을 보면 Serializable을 구현하였다.
안하면 에러나고, 구현했다면
시리얼유니크아이디를 부여하라고 알려주는데 이건 사용자가 원하는 값을 지정할수있음.
또한 비밀번호같이 보안을 요하는/민감한 필드인 경우 타입명앞에 transient 라는 키워드를 붙일 수있음
직렬화 작업에 포함되지 않아 입출력 하고나면 null 값 인걸 알 수 있다..
package sh.java.io.user; import java.io.Serializable; import java.time.LocalDateTime; public class User implements Serializable{ //Serializable:마커 인터페이스 /** * serialVersionUID 객체 입출력 시에 정확한 타입인지를 체크하는 식별값 * -부여하지 않는다면 랜덤처리 */ private static final long serialVersionUID = 1L; private String name; private transient String pw; // 객체 입출력 시 값을 제외(필드는 존재하는데 값을 날림) 보안등의 문제로 제외하고싶을때.. //파일에 저장할때부터 없음 null private LocalDateTime createAt; //만약 커스텀 변수면 이것도 Serializable를 참조해야함.. //무조건 Serializable로 이루어져야함. public User(String name, String pw, LocalDateTime createAt) { this.name = name; this.pw = pw; this.createAt = createAt; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPw() { return pw; } public void setPw(String pw) { this.pw = pw; } public LocalDateTime getCreateAt() { return createAt; } public void setCreateAt(LocalDateTime createAt) { this.createAt = createAt; } @Override public String toString() { return "User [name=" + name + ", pw=" + pw + ", createAt=" + createAt + "]"; } }
그 동안은 scanner와 system.out.print만 다뤄봤는데
타입,목적에 따라 다양한 입출력 클래스를 사용할 수 있었다.
byte인지 string인지 혹은 객체를 사용할 것인지에 따라 표를 보고 사용해봐야겠다.
그리고 예외처리는 필수. 값을 입출력할때 비정상 종료 되는 일 없도록.
'공부' 카테고리의 다른 글
1013(20일차) (0) 2023.10.13 1012(19일차) 수정중.. (0) 2023.10.12 1010 (17일차) 예외처리 (2) 2023.10.10 1006(16일차) (0) 2023.10.06 1005(15일차) (0) 2023.10.05 다음글이 없습니다.이전글이 없습니다.댓글