부트캠프(Java)

자바/스프링 부트캠프 17일차( 보조스트림 ,객체직렬화 , 파일)

동곤일상 2025. 2. 25. 00:00
반응형

1) 보조스트림

1-1) BufferedReader

1-2)PrintStream

 

2)객체의 직렬화

2-1) ObjectOutputStream

2-2) ObjectInputStream

 

3) 파일

 


@@ 1) 보조스트림 @@

보조스트림이란?

 1. 기존의 스트림에 새로운기능을 추가

 

 2. 객체 생성시 다른 스트림을 생성자의 매개변수로받는다

 

1-1) BufferedReader

보조스트림이란?

 1. 기존의 스트림에 새로운기능을 추가

 

 2. 객체 생성시 다른 스트림을 생성자의 매개변수로받는다

 ex) new BufferedReader(new InputStreamReader(System.in));

 

 3.BufferedReader의 생성자 : new BufferedReader(Reader)

 

 화면에서 한줄씩 입력받아서 buffered.txt파일에저장

String readLine() : 한줄씩 읽기

 

 

예제

package ex4_bufferedreader;

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;

public class BufferedReaderEx1 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//br : 키보드에서입력된내용을 한줄씩 읽을수있음(readLine())
		System.out.println("저장할 내용을 입력 ( 종료 : ctrl+Z )");
		Writer w = new FileWriter("bufferd.txt");
		String data=null;
		while((data=br.readLine())!= null) {
			System.out.println(data);
			w.write(data+"\n");
		}
		w.flush();w.close();
		br.close();
	}
}

 

예시2)

 

화면에서 파일명을 입력받고 출력 시작할 시작라인 , 출력라인수를 입력받아서
 시작라인부터 라인수까지의 내용을 화면에출력

 * 결과
 * 파일명입력
 * src/ex1_InputStream/InputStreamEx1.java
 * 시작라인
 * 1
 * 라인수
 * 3

package ex4_bufferedreader;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Exam1 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("파일명 입력");
		String filename = br.readLine();
		
		System.out.println("시작 라인 : ");
		String a = br.readLine();
		int stl = Integer.parseInt(a);
		
		System.out.println("라인 수 : ");
		String b = br.readLine();
		int len = Integer.parseInt(b);
		
		BufferedReader br2 = new BufferedReader(new FileReader(filename));
		String data = null;
		int line=0,cnt=0;//line:라인수 cnt 출력한 라인수
		while((data=br2.readLine())!=null) {
			line++;
			if(line<stl)continue;
			if(cnt>=len)break;
			++cnt;
			System.out.println(line+":"+data);
		}br.close();br2.close();

	}
}

readLine() 은 한줄씩 읽는것임을 명심하자..

파일명 입력

src/ex1_InputStream/InputStreamEx1.java

시작 라인 :

4

라인 수 :

8

4:import java.io.InputStream;

5:

6:public class InputStreamEx1 {

7: public static void main(String[] args) throws IOException{

8: InputStream in = System.in;// 키보드입력

9: int data=0;

10: //in.read() : 1byte 씩 읽기 (한글: 2byte)

11: while((data=in.read()) != -1) {//ctrl+z (EOF) : 더이상안한다고판단

 

 


 1-2)  PrintStream 


 * 1. OutputStream 클래스의 하위클래스 --> 바이트형 출력스트림
 * 2.write 기능을 다양하게 확장함 --> print , println , printf
 *    --> 모든 자료형을 출력 , 예외처리생략가능(IOException)
 *  3.표준출력(System.out) 표준오류(System.err) 객체의자료형
 *  4.객체생성시 바이트형출력스트림(OutputStream)을 매개변수로받는다
 *     new PrintStrema(OutputStream)

package ex5_printStream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintStreamEx1 {
	public static void main(String[] args) throws FileNotFoundException {
		FileOutputStream fos = new FileOutputStream("print.txt");
		PrintStream ps =new PrintStream(fos);
		ps.println("홍길동");
		ps.println(1234);
		ps.println(true);//println은 그냥 그대로를 출력해줌
		ps.write(65);//FileOutputStream은 byte단위로 저장되므로 아스키코드가나올것임
		ps.flush();
		ps.close();
	}
}

 

 

예제

package ex5_printStream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

//예외발생한내용을 error.log파일에 PrintStream이용해출력
//2025-02-24 HH:mm:ss --> FOr input string : "a"

public class Exam1 {
	public static void main(String[] args) throws FileNotFoundException {
		PrintStream ps = new PrintStream(new FileOutputStream("error.log",true));
		try {
			String str = "a";
			System.out.println(Integer.parseInt(str));
			
		}
		catch(Exception e) {
			LocalDateTime data = LocalDateTime.now();
			DateTimeFormatter f =DateTimeFormatter.ofPattern("yyyy-MM-dd  HH:mm:ss");
//			SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
//			ps.println(sf.format(new Date()+" => "+e.getMessage()));
			ps.print(f.format(data));
			ps.print("--->");
			ps.println(e.getMessage());
			System.out.println(e.getMessage());//이내용을 error.log에출력
			e.printStackTrace(ps);
			//ps에 에러메시지를 보냄!!!(콘솔창에나타나지않고
			//error.log파일에 들어감
			
		}
		finally {
			ps.close();
		}
	}
}


 

cmd창에 ipconfig 입력 시 네트워크정보가뜸

 

ping +기본게이트웨이 주소(컴퓨터마다 다를거임) 를 입력하면

네트워크가 작동이 잘 되는지 확인가능

 


 p.getInputStream() : ping 외부프로세스로부터 Data를 읽기
  new InputStreamReader(InputStream,encoding방식); : UTF-8이 기본
    --> 텍스트의 Encoding 방식 설정

Process : 현재실행중인 프로세스

package ex5_printStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;

public class PrintStreamEx2 {
	public static void main(String[] args) throws IOException {
		String [] cmds = {"ping", "게이트웨이주소"};
		Process p = Runtime.getRuntime().exec(cmds);
		Reader r = new InputStreamReader(p.getInputStream(),"EUC-KR");
				//인코딩떄문에 한글이깨지는지 , 바이트 수 때문에깨지는지 판단하자
		//참고로 Reader는 2바이트씩읽으므로 한글이 깨질일이없다 (인코딩방식문제)
		int data=0;
		PrintStream ps = new PrintStream(new FileOutputStream("ping.txt"));
		while((data=r.read())!= -1) {
			ps.print((char)data);
			System.out.print((char)data);
		}
	}

}

현재프로세스의 정보를 가져옴

 


2)객체의 직렬화

 

2-1) ObjectOutputStream

객체를 외부로전송할 수 있는 출력스트림

 


 * ObjectOutputStream예제
 * 1. 객체를 외부로전송 할 수 있는 스트림
 * 2. 외부전송이 가능한 객체는 반드시 Serializable 인터페이스를 구현해야함
 *  ==> 직렬화
 *  ==> Serializable 인터페이스를 구현하지않은 객체를 외부전송시 
 *   NotSerializableException발생


 *  3.ObjectOutputStream으로 전송된객체는 ObjectInputStream객체로읽음
 * 
 * Serializable 인터페이스의 멤버 없음!!

package ex6_objectStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

@SuppressWarnings("serial")//warning표시 안 하겠단 에노테이션

class Customer implements Serializable{//꼭 구현!
	private String name;
	private  int age;
	//transient : 직렬화 대상의 객체에서 해당멤버는 제외
	private transient int pw;
	public Customer(String name, int age,int pw) {
		super();
		this.name = name;
		this.age = age;
		this.pw = pw;
	}
	@Override
	public String toString() {
		return name +","+ age  ;
	}
	
}
public class ObjectoutputSteamEx1 {
	public static void main(String[] args) throws IOException {
		//fos스트림의 목적지 : object.ser
		FileOutputStream fos = new FileOutputStream("object.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos/*목적지*/);
		Customer c1 = new Customer("하이", 44,9844);
		Customer c2 = new Customer("루", 24,5312);
		System.out.println(c1);
		System.out.println(c2);
		
		oos.writeObject(c1);//c1객체를 object.ser로 전송
		oos.writeObject(c2);//c2객체를 object.ser로 전송
		oos.close();
		fos.close();
		
		
		

	}
}

하이,44,9844

루,24,5312

 


2-2)ObjectInputStream

ObjectOutputStream으로출력된 내용을 ObjectInputStream으로 읽는다.

package ex6_objectStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

/*
 * ObjectOutputStream을 이용해 객체를 저장한 Object.ser파일 읽기
 */
public class ObjectInputStreamEx1 {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.ser"));
		int data=0;
		Customer c1 = (Customer) ois.readObject();//object->Customer로다운캐스팅
		Customer c2 = (Customer) ois.readObject();
		System.out.println(c1);
		System.out.println(c2);
		
	}
}

 

파일에서가져올떄 pw가 0으로초기화 되어있음!!

transient 선언을 했기때문!!!!

하이,44,0

루,24,0

 


 

예제!!!! (객체를 ObjectOutputStream이용해서 파일에저장하고

 

ObjectInputStream을 이용해서 다시 읽어보자)

 

package ex6_objectStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo{
	protected String name;
	protected String password;
	public UserInfo() {};
	public UserInfo(String name , String password) {
		this.name = name;
		this.password = password;
	}
	public String toString() {
		return name+","+password;
	}
}
//-------------------------------------------------------------------
class User extends UserInfo implements Serializable{
	private int age;
	public User(String name , String password , int age) {
		super(name,password);
		this.age = age;
	}
	public String toString() {
		return super.toString()+","+age;
	}
}

//---------------------------------------------------------------------------------

public class ObjectOutputStreamEx2 {
	public static void main(String[] args) throws  IOException, ClassNotFoundException {
		
		ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("object2.ser"));
		UserInfo u1 = new User("유동곤", "1233", 26);
		UserInfo u2 = new User("김삿갓", "643", 16);
		os.writeObject(u1);
		os.writeObject(u2);
		System.out.println(u1);
		System.out.println(u2);
		os.close();	
	}
}
package ex6_objectStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStreamEx2 {

	public static void main(String[] args) throws  IOException, ClassNotFoundException {
		FileInputStream fis = new FileInputStream("object2.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);
		UserInfo u1= (UserInfo)ois.readObject();
		UserInfo u2= (UserInfo)ois.readObject();
		System.out.println(u1);
		System.out.println(u2);
	}
}

null,null,26

null,null,16

 

UserInfo 가  Serializable를 구현하지않았기에

 

부모멤버의 부분은

아무것도저장되지않은것을 확인 (직렬화될수없음)

 


이와같이 강제적으로

부모객체의멤버를 직렬화해서 추가하는방법을 사용했다

class User extends UserInfo implements Serializable{
	private int age;
	public User(String name , String password , int age) {
		super(name,password);
		this.age = age;
	}
	public String toString() {
		return super.toString()+","+age;
	}
	
	//부모객체의 멤버를 직렬화에 추가하기
	//User클래스내에서 자동으로 메서드를실행함
	private void writeObject(ObjectOutputStream out) throws IOException{
		out.writeUTF(name);//protected이므로 접근가능
		out.writeUTF(password);//부모의문자열을 OutputStream에저장
		out.defaultWriteObject();
		//나머지것(age)을 다 보내란 뜻
	}
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
		name = in.readUTF();
		password = in.readUTF();
		in.defaultReadObject();
	}
}

User를 다음과같이 변경했다면

파일에 다시저장 후

출력해보면

유동곤,1233,26

김삿갓,643,16

 

 


@@ 3)File 클래스 @@


 * File클래스
* -파일이나 폴더의 정보를 관리하는 클래스
 * -new File(String) : 경로
 * - new File(String,String) : 경로, 하위경로
 * -윈도우 :  \\ , /
 * -리눅스 :  /

package ex7_other;

import java.io.File;

public class FileEx1 {
	public static void main(String[] args) {
		System.out.println("File.separator : "+File.separator);
		String filePath = "c:/";
		//f1 : c:/ 폴더의정보
		File f1 = new File(filePath);
		//f1.list() : 하위폴더/파일의 정보이름 리턴
		String[] files = f1.list();
		for (String f : files) {//f : c:/폴더의 하위목록의 이름
			System.out.println(f);
			File f2 = new File(filePath,f);//상위경로 , 하위경로
			if(f2.isDirectory()) {//폴더??
				System.out.printf("%s:디렉토리\n",f);
			}
			else {
				//f.length() 파일의 크기
				//%,d : 10진정수출력시 세자리마다 , 를 표시해 출력
				System.out.printf("%s:파일(%,dbytes)\n",f,f.length());
			}
		}
		
	}
}
File.separator : \
$Recycle.Bin
$Recycle.Bin:디렉토리
$SysReset
$SysReset:디렉토리
312_hskibt_kaosheng
312_hskibt_kaosheng:디렉토리
Documents and Settings
Documents and Settings:디렉토리
DumpStack.log.tmp
DumpStack.log.tmp:파일(17bytes)
hiberfil.sys
hiberfil.sys:파일(12bytes)
hp
hp:디렉토리
icon
icon:디렉토리
Intel
Intel:디렉토리
MSOCache
MSOCache:디렉토리
pagefile.sys
pagefile.sys:파일(12bytes)
PerfLogs
PerfLogs:디렉토리
pexels-pixabay-33109.jpg
pexels-pixabay-33109.jpg:파일(24bytes)
Program Files
Program Files:디렉토리
Program Files (x86)
Program Files (x86):디렉토리
ProgramData
ProgramData:디렉토리
Recovery
Recovery:디렉토리
swapfile.sys
swapfile.sys:파일(12bytes)
System Volume Information
System Volume Information:디렉토리
system.sav
system.sav:디렉토리
temp1
temp1:디렉토리
Users
Users:디렉토리
Windows
Windows:디렉토리
Windows.old
Windows.old:디렉토리
스크린샷 2025-02-17 171548.png
스크린샷 2025-02-17 171548.png:파일(26bytes)

 * File 클래스의 주요메서드


 * 1.getAbsolutePath() : 절대경로(전체경로)
 * 2.mkdir() : 하위폴더 1개 생성 ,폴더생성:true 리턴 실패 else
 * 3.mkdirs() : 여러개의 하위 폴더
 * 4 createNewFile() : 파일생성, 파일생성 성공:ture 리턴
 * 5.getName() : 파일의 이름
 * 6.length() : 파일의크기 (바이트)
 * 7.exists() : 존재여부판단 , 존재하면 true리턴 , 없는파일이면 false
 * 8.f2.renameTo(f3) : f2의 이름을 f3로 변경해라
 * 9.lastModified 

package ex7_other;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;

public class FileEx2 {
	public static void main(String[] args) throws IOException {
		File f1 = new File("c:/temp1");
		System.out.printf("%s 폴더 생성 :%b\n",f1.getAbsolutePath(),f1.mkdir());
		File f2 = new File("c:/temp1/test.txt");
		System.out.printf("%s 파일생성:%b\n",f2.getAbsolutePath(),f2.createNewFile());
		System.out.printf("파일이름 : %s,파일크기 : %d\n",f2.getName(),f2.length());
		//폴더생성과 파일생성 까지만 가능 (내용 관련은 스트림이용)
		
		
		File f3 = new File("c:/temp1/test2.txt");
		if(f3.exists()) {
			System.out.println(f3.getName()+"파일 존재");
		}
		else {
			System.out.println(f3.getAbsolutePath()+"파일 존재하지않음");
		}
		System.out.printf("%s-->%s 이름변경 :%b\n",f2.getName(),f3.getName(),f2.renameTo(f3));
		//lastMoidfied() : 1970년이후부터 파일수정시간까지 밀리초로리턴
		System.out.println("파일의 최종수정시간 : "+f3.lastModified());
		//파일의최종수정시간 : 년월일 시분초로출력해보자
		String last = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(f3.lastModified()));
			//new Data(lastMoidfied): lastMoidfied에 해당하는 일 시로 만들어줌
		System.out.println("파일의 최종수정시간 : "+last);
		
		//LocalDateTime을 이용한방법
		LocalDateTime ldt = Instant.ofEpochMilli(f3.lastModified()).atZone(ZoneId.systemDefault())
		.toLocalDateTime();
		DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		System.out.println("파일의 최종수정시간(LocalDatetime) : "+ldt.format(pattern));
		
		System.out.printf("%s 파일삭제 : %b\n ",f3.getName(),f3.delete());
		
	}

}

c:\temp1 폴더 생성 :false

c:\temp1\test.txt 파일생성:false

파일이름 : test.txt,파일크기 : 0

c:\temp1\test2.txt파일 존재하지않음

test.txt-->test2.txt 이름변경 :true

파일의 최종수정시간 : 1740375874467

파일의 최종수정시간 : 2025-02-24 14:44:34

파일의 최종수정시간(LocalDatetime) : 2025-02-24 14:44:34

test2.txt 파일삭제 : true

실제윈도우경로에 들어가보면 파일이생성되고 삭제되는것을 볼 수 있다.

 


package ex7_other;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileEx3 {
	public static void main(String[] args) throws IOException {
		File f = new File("data.txt");
		if(!f.exists()) {
			System.out.println(f.getName()+"파일 존재X");
//			FileOutputStream fos = new FileOutputStream(f);
//			byte[] buf ="안녕하세요".getBytes();
//			fos.write(buf);
//			fos.flush();
//			fos.close();
			return;
		}
		FileInputStream fis = new FileInputStream(f);
		int len=0;
		byte[] buf = new byte[fis.available()];
		while((len=fis.read(buf))!= -1) {
			System.out.println(new String(buf,0,len));
		}
		fis.close();
		f.delete();
	}

}

안녕하세요

 

1번 더 실행후

 

data.txt파일 존재X

FileInputStream  , FileOutputStream 모두

생성자에 파일이 들어갈수있음..>!!!!

 


예제)


  c:/widows폴더의 하위폴더의갯수와 파일의갯수,파일의 총 크기출력

package ex7_other;

import java.io.File;

public class Exam1 {
	public static void main(String[] args) {
		File f = new File("c:/windows");
		String[] list = f.list();
		int dCount=0;
		int fCount=0;
		long fSize=0;
		for (String s : list) {
		
			System.out.println("name:"+s);
			File f2 = new File(f,s);//f의 하위폴더 s
			
			if(f2.isFile()) {
				System.out.printf("%s : 파일(%dbyte)\n",f2,f2.length());
				fCount++;
				fSize+=f2.length();
			}
			else {
				System.out.printf("%s : 폴더\n",f2.getAbsoluteFile());
				dCount++;
			}
			
		}System.out.println();
		System.out.println("폴더의 갯수 : "+dCount);
		System.out.println("파일의 갯수 : "+fCount);
		System.out.printf("파일의 총 크기 : %,d",fSize);
	
	}
}

폴더의 갯수 : 85

파일의 갯수 : 26

파일의 총 크기 : 6,147,541(byte)

 

 


SequenceStream


 * SequenceStream 
 *  -여러개의 스트림을 하나의 스트림으로 합 해주는 스트림

package ex7_other;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Vector;

public class SequenceStreamEx1 {
	public static void main(String[] args) throws IOException {
		File f = new File("src/ex7_other");
		String[] files = f.list();
		Vector<InputStream> v = new Vector<InputStream>();
		for(String file : files) {
			File f2 = new File(f,file);
			if(f2.isFile()) {
				v.add(new FileInputStream(f2));//f2파일을 vector에 저장
				}
		}
		//Enumeration v.elements();
		//s :[new FileInputStream("Exam1.java),("FileEx1.java)..... 등
		//  여러개의 스트림을 한개의 스트림으로 연결시켜줌
		SequenceInputStream s =  new SequenceInputStream(v.elements());
		FileOutputStream fos = new FileOutputStream("file예제.txt");
		int data = 0;
		byte[] buf = new byte[s.available()];//s의 읽기가능한 바이트 수
		while((data=s.read(buf))!= -1) {
			fos.write(buf,0,data);
			//File예제.txt에 내용을 출력해보자
		}
		
		fos.flush();
		fos.close();
		s.close();
	}
}

사진으로모두담을 수 없지만 src/ex7_other의 모든코드가 한군데에 모여있음.