기록
  • 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
    댓글