지구정복

[JAVA] 11/25 | 콘솔입출력, 문자변환보조스트림, 기본타입입출력보조스트림, 객체입출력보조스트림, 버퍼, 파일채널, 파일복사, excel우편번호검색하기 본문

데이터 엔지니어링 정복/JAVA & JSP

[JAVA] 11/25 | 콘솔입출력, 문자변환보조스트림, 기본타입입출력보조스트림, 객체입출력보조스트림, 버퍼, 파일채널, 파일복사, excel우편번호검색하기

eeaarrtthh 2020. 11. 27. 02:09
728x90
반응형

정리

영구저장
	로컬(프로그램과 같이 저장되어 있는) - File
	java.io -> java.nio
	File 1018p(IO), 1102p(NIO)
	Stream (읽고싶은 단위를 읽는다.)
		input - read()를 사용 / output - write()를 사용
		InputStream, OutputStream / Reader, Writer
		1차 스트림 / 보조 스트림(2차스트립)
		=> 클래스가 존재 996p

 

 

ㅇ콘솔 입출력

콘솔은 시스템을 사용하기 위해 키보드로 입력을 받고 화면으로 출력하는 소프트웨어를 말한다.

유닉스나 리눅스 운영체제는 터미널에 해당되고 윈도우는 명령프롬프트에 해당한다.

콘솔로 데이터를 입력받을 때 System.in을 사용하고, 출력할때는 System.out을 사용한다.

 

System.in은 InputStream 타입의 필드이므로 다음과 같이 참조가 가능하다.

InputStream is = System.in;

키보드로부터 어떤 키가 입력되었는지 확인하려면 InputStream의 read() 메소드로 한 바이트를 읽으면 된다.

리턴된 int 값에는 십진수 아스키코드가 들어있다.

숫자로된 아스키 코드 대신에 키보드에서 입력한 문자를 직접 얻고 싶다면 read() 메소드로 읽은 아스키 코드를

char로 타입변환하면 된다.

char inputChar = (char) is.read();

 

package SystemEx01;

import java.io.IOException;
import java.io.InputStream;

public class SystemEx01 {

	public static void main(String[] args) {
		InputStream is = null;
		
		try {
			is = System.in;
			System.out.print("데이터 입력: ");
			
			int data = is.read();
			System.out.println("입력 데이터: "+data);
			System.out.println
			("입력 데이터: "+(char)data);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(is != null) try {is.close();} catch(IOException e) {}
		}
	}
}


데이터 입력: 123
입력 데이터: 49
입력 데이터: 1
package SystemEx01;

import java.io.IOException;
import java.io.InputStream;

public class SystemInExample1 {

	public static void main(String[] args) {
		System.out.println("== 메뉴 ==");
		System.out.println("1. 예금조회");
		System.out.println("2. 예금출금");
		System.out.println("3. 예금입금");
		System.out.println("4. 종료하기");
		System.out.print("메뉴를 선택하세요 : ");
		
		InputStream is = System.in;
		
		try {
			char inputChar = (char) is.read();
			switch(inputChar) {
			case '1':
				System.out.println("예금조회 선택했습니다.");
				break;
			case '2':
				System.out.println("예금출금 선택했습니다.");
				break;
			case '3':
				System.out.println("예금입금 선택했습니다.");
				break;
			case '4':
				System.out.println("종료하기 선택했습니다.");
				break;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(is != null) try {is.close();} catch(IOException e) {}
		}
	}
}


== 메뉴 ==
1. 예금조회
2. 예금출금
3. 예금입금
4. 종료하기
메뉴를 선택하세요.1
예금조회 선택했습니다.

 

 

ㅇ문자변환 보조 스트림

p1029/1031
한글을 입력하고 싶으면 문자변환 보조 스트림을 이용해야 한다.

이는 문자셋의 종류를 지정할 수 있기 때문에 다양한 문자를 입출력할 수 있다.

 

InputStramReader 사용

package SystemEx01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class SystemEx02 {

	public static void main(String[] args) {
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		
		try {
			is = System.in;				//시스템으로부터 입력받기
			isr = new InputStreamReader(is);	//바이트입력스트림에서 문자입력스트림으로 변환
			br = new BufferedReader(isr);		//버퍼를 이용해 가속화시키기
			System.out.print("데이터 입력: ");
			
			System.out.println("입력 데이터: "+(char)br.read());
			System.out.println("입력 데이터: "+(char)br.read());
			System.out.println("입력 데이터: "+(char)br.read());
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(isr != null) try {isr.close();} catch(IOException e) {}
			if(is != null) try {is.close();} catch(IOException e) {}
			if(br != null) try {br.close();} catch(IOException e) {}
		}
	}
}


데이터 입력: 가나다
입력 데이터: 가
입력 데이터: 나
입력 데이터: 다

위 코드를 BufferedReader에 한꺼번에 다 사용해보자.

br = new BufferedReader(new InputStreamReader(System.in));

또한 출력할 때도 readLine()으로 한꺼번에 출력시키자.

System.out.println("입력 데이터: "+(char)br.readLine());

 

 

 

ㅇ기본 타입 입출력 보조 스트림

1037

바이트 스트림은 바이트 단위로 입출력하기 때문에 자바의 기본 데이터 타입단위로 입출력할 수 없다.

그러나 DataInputStream과 DataOuputStream 보조 스트림을 연결하면 기본 데이터 타입으로 입출력할 수 있다.

 

.dat 파일은 시스템 운영에 필요한 데이터를 저장하는 용도로 주로 사용, 파일을 만든 프로그램과 관련된 특정 정보를 저장하는 일반 데이터 파일이다.

 

-DataOuputStream

package SystemEx01;

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataIOEx01 {

	public static void main(String[] args) {
		DataOutputStream dos = null;
		
		try {
			dos = new DataOutputStream(new FileOutputStream("./value.dat"));
			
			dos.writeInt(2020);
			dos.writeUTF("UTF-8형식으로 저장");
			dos.writeFloat(1.8f);
				
			System.out.println("출력 완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(dos != null) try {dos.close();} catch(IOException e) {}
		}
	}
}

 

-DataInputStream

package SystemEx01;

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

public class DataIOEx02 {

	public static void main(String[] args) {
		DataInputStream dis = null;
		
		try {
			dis = new DataInputStream(new FileInputStream("./value.dat"));
			
			System.out.println(dis.readInt());
			System.out.println(dis.readUTF());
			System.out.println(dis.readFloat());
			
			System.out.println("출력완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(dis != null) try {dis.close();} catch(IOException e) {}
		}
	}
}


2020
UTF-8형식으로 저장
1.8
출력완료

 

-한 클래스에서 DataInputStream과 DataOutputStream 동시에 사용하기

package SystemEx01;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class DataInputOutputStreamExample{

	public static void main(String[] args) throws Exception {
		FileOutputStream fos = new FileOutputStream("./primitive.dat");
		DataOutputStream dos = new DataOutputStream(fos);
		
		dos.writeUTF("홍길동");
		dos.writeDouble(95.5);
		dos.writeInt(1);
		
		dos.writeUTF("김자바");
		dos.writeDouble(90.3);
		dos.writeInt(2);
		
		dos.flush(); dos.close(); fos.close();
		
		FileInputStream fis = new FileInputStream("./primitive.dat");
		DataInputStream dis = new DataInputStream(fis);
		
		for(int i=0; i<2; i++) {
			String name = dis.readUTF();
			double score = dis.readDouble();
			int order = dis.readInt();
			System.out.println(name + " : " + score + " : " + order);
		}
	}
}


홍길동 : 95.5 : 1
김자바 : 90.3 : 2

 

 

ㅇ객체 입출력 보조 스트림

1043

자바는 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수가 있다. 객체는 문자가 아니기 때문에 바이트 기반 스트림으로 출력해야 한다. 객체를 출력하기 위해서는 객체의 데이터(필드값)를 일렬로 늘어선 연속적인 바이트로 변경해야 하는데, 이것을 객체 직렬화(serialization)라고 한다.

 

반대로 파일에 저장되어 있거나 네트워크에서 전송된 객체를 읽을 수도 있는데, 입력 스트림으로부터 읽어들인 연속적인 바이트를 객체로 복원하는 것을 역직렬화(deserialization)라고 한다.

 

-데이터 만들기

package SystemEx01;

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

public class ObjectIOEx01 {

	public static void main(String[] args) {
		ObjectOutputStream oos = null;
		
		try {
			oos = new ObjectOutputStream(new FileOutputStream("./data.dat"));
			
			//내장 객체, 기본 객체
			String[] names = {"홍길동", "박문수", "이몽룡"};
			int[] ages = {55, 23, 47};
			double[] weight = {75.3, 67.9, 58.6};
			
			oos.writeObject(names);
			oos.writeObject(ages);
			oos.writeObject(weight);
			
			System.out.println("저장완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(oos != null) try {oos.close();} catch(IOException e) {}
		}
	}
}

 

-데이터 읽어오기

package SystemEx01;

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

public class ObjectIOEx02 {

	public static void main(String[] args) {
		ObjectInputStream ois = null;
		
		try {
			ois = new ObjectInputStream(new FileInputStream("./data.dat"));
			
			String[] names = (String[])ois.readObject();
			int[] ages = (int[])ois.readObject();
			double[] weights = (double[])ois.readObject();
			
			for(int i=0; i<names.length; i++) {
				System.out.println(names[i]);
				System.out.println(ages[i]);
				System.out.println(weights[i]);
			}
			
			System.out.println("출력완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(ois != null) try {ois.close();} catch(IOException e) {}
		}
	}
}


홍길동
55
75.3
박문수
23
67.9
이몽룡
47
58.6
출력완료

 

-사용자 정의 객체 넣고 읽어오기

 

Person 클래스 정의

직렬화를 위해 시리얼라이저블 인터페이스를 구현한다.

package SystemEx01;

public class Person implements Serializable {
	private String name;
	private String phone;
	private int age;
	
	public Person(String name, String phone, int age) {
		this.name = name;
		this.phone = phone;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", phone=" + phone + ", age=" + age + "]";
	}	
}

main클래스

package SystemEx01;

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

public class ObjectIOEx03 {

	public static void main(String[] args) {
		ObjectOutputStream oos = null;
		
		try {
			oos = new ObjectOutputStream(new FileOutputStream("./serial.dat"));
			
			Person p = new Person("홍길동", "010-1111-1111", 30);
			oos.writeObject(p);
			
			System.out.println("출력완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(oos != null) try {oos.close();} catch(IOException e) {}
		}
	}
}

 

만들어진 serial.dat의 데이터를 읽어오기

package SystemEx01;

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

public class ObjectIOEx04 {

	public static void main(String[] args) {
		ObjectInputStream ois = null;
		
		try {
			ois = new ObjectInputStream(new FileInputStream("./serial.dat"));
			
			Person p = (Person)ois.readObject();
			System.out.println(p);
			
			System.out.println("출력완료");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(ois != null) try {ois.close();} catch(IOException e) {}
		}
	}
}


Person [name=홍길동, phone=010-1111-1111, age=30]
출력완료

 

 

-serialVersionUID 필드

직렬화된 객체를 역직렬화할 때는 직렬화했을 때와 같은 클래스를 사용해야 한다.

클래스의 이름이 같더라도 클래스의 내용이 변경되면, 역직렬화는 실패한다.

 

serialVersionUID는 같은 클래스임을 알려주는 식별자 역할을 하는데, Serializable 인터페이스를 구현한 클래스를 컴파일하면 자동적으로 serialVersionUID 정적 필드가 추가된다.

 

 

-직렬화되는 필드와 그렇지 못한 필드 확인 예제

package SystemEx01;

import java.io.Serializable;

public class ClassA implements Serializable {
	//직렬화에 포함
	int field1;
	ClassB field2 = new ClassB();
	
	//직렬화에서 제외
	static int field3;
	transient int field4;
}
package SystemEx01;

import java.io.Serializable;

public class ClassB implements Serializable {
	//직렬화에 포함
	int field1;
}
package SystemEx01;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializableWriter {

	public static void main(String[] args) throws Exception {
		FileOutputStream fos = new FileOutputStream("./Object.dat");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		
		ClassA classA = new ClassA();
		classA.field1 = 1;
		classA.field2.field1 = 2;
		classA.field3 = 3;
		classA.field4 = 4;
		
		oos.writeObject(classA);
		oos.flush(); oos.close(); fos.close();
	}
}
package SystemEx01;

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class SerializableReader {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("./Object.dat");
		ObjectInputStream ois = new ObjectInputStream(fis);
		
		ClassA v = (ClassA)ois.readObject();
		System.out.println("field1 :" + v.field1);
		System.out.println("field2.field1 :" + v.field2.field1);
		System.out.println("field3 :" + v.field3);
		System.out.println("field4 :" + v.field4);
	}
}

먼저 SerializableWriter 클래스를 실행하면 ClassA 객체를 직렬화해서 Object 파일에 저장한다.
그리고나서 SerializableReader클래스를 실행하면 Object 파일에 저장된 데이터를 읽고 ClassA 객체로 역직렬화한다. 
실행결과를 보면 field1과 field2는 값이 복원되는 것을 알 수 있으나,
static 필드인 field3과 transient 필드인 field4는 값이 복원되지 않는다.
Object 파일에는 field1과 field2의 데이터만 저장되어 있기 때문이다.

 

 

-RandomAccessFile 사용하기

 

package SystemEx01;

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileEx01 {

	public static void main(String[] args) {
		RandomAccessFile raf = null;
		
		try {
			// rw - read/write 읽기와 쓰기를 동시에 할 수 있다.
			raf = new RandomAccessFile("./score.dat", "rw");
			
			int[] scores = {
				1, 100, 90, 90,
				2, 70, 90, 100,
				3, 100, 100, 100
			};
			
			for(int i=0; i<scores.length; i++) {
				raf.writeInt(scores[i]);
				
				//바이트 값이 출력된다.
				System.out.println("쓰기 위치 : " + raf.getFilePointer());
			}
			System.out.println("출력 완료");
			
			//읽을 위치값 가져오기 0바이트부터
			raf.seek(0);
			
			while(true) {
				System.out.println(raf.readInt());
			}
		
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch(EOFException e) {
			System.out.println("읽기전용");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(raf != null) try {raf.close();} catch(IOException e) {}
		}
	}
}


쓰기 위치 : 4
쓰기 위치 : 8
쓰기 위치 : 12
쓰기 위치 : 16
쓰기 위치 : 20
쓰기 위치 : 24
쓰기 위치 : 28
쓰기 위치 : 32
쓰기 위치 : 36
쓰기 위치 : 40
쓰기 위치 : 44
쓰기 위치 : 48
출력 완료
1
100
90
90
2
70
90
100
3
100
100
100
읽기전용

 

 

-Properties 저장하고 읽어오기

package SystemEx01;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesEx01 {

	public static void main(String[] args) {
		Properties p = new Properties();
		p.setProperty("id", "anby");
		p.setProperty("pass", "1234");
		p.setProperty("addr", "192.168.0.11");
		
		System.out.println(p.toString());
		
		FileWriter fw = null;
		
		try {
			fw = new FileWriter("./config.properties");
			p.store(fw, "System Config");
			
			System.out.println("출력완료");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if( fw != null) try { fw.close(); } catch(IOException e) {}
		}
	}
}
package SystemEx01;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class PropertiesEx02 {

	public static void main(String[] args) {
		Properties p = new Properties();
		
		FileReader fr = null;
		try {
			fr = new FileReader("./config.properties");
			p.load(fr);
			
			System.out.println(p.getProperty("id"));
			System.out.println(p.getProperty("pass"));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if( fr != null) try { fr.close(); } catch(IOException e) {}
		}
	}
}

 

ㅇ버퍼

1114~1119

NIO에서는 데이터를 입출력하기 위해 항상 버퍼를 사용해야 한다.

버퍼는 읽고 쓰기가 가능한 메모리 배열이다.

 

버퍼는 저장되는 데이터 타입에 따라 분류될 수 있고, 어떤 메모리를 사용하느냐에 따라 다이렉트와 넌다이렉트로 분류된다.

넌다이렉트 버퍼는 JVM이 관리하는 힙 메모리 공간을 이용하는 버퍼이고,

다이렉트 버퍼는 운영체제가 관리하는 메모리 공간을 이용하는 버퍼이다.

구분 넌다이렉트 버퍼 다이렉트 버퍼
사용하는 메모리 공간 JVM의 힙 메모리 운영체제의 메모리
버퍼 생성 시간 버퍼 생성이 빠르다. 버퍼 생성이 느리다.
버퍼의 크기 작다. 크다.(큰 데이터 처리시 유리)
입출력 성능 낮다. 높다.(입출력 빈번할 때 유리)

-버퍼 생성

allocate()  : JVM 힙 메모리에 넌다이렉트 버퍼를 생성

weap()

package SystemEx01;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;

public class DirectBufferCapacityExample {

	public static void main(String[] args) {
		ByteBuffer b = ByteBuffer.allocateDirect(100);
		System.out.println("저장용량: "+b.capacity()+" byte");
		
		CharBuffer c = ByteBuffer.allocateDirect(100).asCharBuffer();
		System.out.println("저장용량: "+c.capacity()+" char");
		
		IntBuffer i = ByteBuffer.allocateDirect(100).asIntBuffer();
		System.out.println("저장용량: "+i.capacity()+" int");

	}
}

 

 

-버퍼의 위치속성

속성에는 네 가지가 있다.

position : 현재 읽거나 쓰는 위치값. 인덱스 값이기 때문에 0부터 시작하며 limit값보다 클 수가 없다. 

                     만약 limit값과 같아진다면 더 이상 데이터를 쓰거나 읽을 수 없다는 뜻이다.

limit : 버퍼에서 읽거나 쓸 수 있는 위치의 한계. 이 값은 capacity보다 클 수 없다. 최초에 버퍼를 만들면 capacity와 같은 값이다.

capacity : 버퍼의 최대 데이터 개수(메모리 크기)를 의미

mark : reset()메소드를 실행했을 때에 돌아오는 위치를 지정하는 인덱스값으로 mark() 메소드로 지정할 수 있다.

             지정할 때 주의할 점은 position 값보다 큰 값으로 지정할 수 없다. 또한 position이나 limit가 mark값보다 작으면

            mark값은 자동 제거되고, mark가 없는 상태에서 reset() 메소드를 호출하면 에러가 난다.

 

-주요 메소드

flip() 메소드 : limit 값을 현재 position 값으로 설정되고, position은 0번 인덱스로 초기화된다.mark() 메소드 : mark 값을 현재 posiotion값으로 설정한다.reset() 메소드 : position 값을 mark 값으로 이동시킨다.rewind() 메소드 : limit값은 변하지 않지만 position 값은 0번 인덱스로 초기화된다.clear() 메소드 : 버퍼의 세 가지 속성을 초기화한다. limit는 capacity로, position은 0으로, mark는 자동 삭제된다.compact() 메소드 : 현재 position부터 limit 전 데이터가 0번 인덱스로 복사되고 현재 position은 복사된 데이터 다음 위치로                                         이동한다.

package SystemEx01;

import java.nio.Buffer;
import java.nio.ByteBuffer;

public class BufferExample {

	public static void main(String[] args) {
		System.out.println("[7바이트 크기로 버퍼 생성]");
		//다이렉트 버퍼 생성
		ByteBuffer buffer = ByteBuffer.allocateDirect(7);
		printState(buffer);
		
		buffer.put((byte)10);
		buffer.put((byte)11);
		System.out.println("[2바이트 저장후]");
		printState(buffer);
		
		buffer.put((byte)12);
		buffer.put((byte)13);
		buffer.put((byte)14);
		System.out.println("[3바이트 저장후]");
		printState(buffer);
		
		buffer.flip();
		System.out.println("[flip() 실행후]");
		printState(buffer);
		
		buffer.get(new byte[3]);
		System.out.println("[3바이트 읽은후]");
		printState(buffer);
		
		buffer.mark();
		System.out.println("[---현재 위치를 마크 해놓음---]");
		
		buffer.get(new byte[2]);
		System.out.println("[2바이트 읽은후]");
		printState(buffer);
		
		buffer.reset();
		System.out.println("[---position을 마크 위치로 옮김---]");
		printState(buffer);
		
		buffer.rewind();
		System.out.println("[rewind() 실행후");
		printState(buffer);
		
		buffer.clear();
		System.out.println("[clear() 실행후");
		printState(buffer);
		

	}
	public static void printState(Buffer buffer) {
		System.out.print("\tposition:" + buffer.position() + ", ");
		System.out.print("\tlimit:" + buffer.limit() + ", ");
		System.out.println("\tcapacity:" + buffer.capacity());
	}
}




[7바이트 크기로 버퍼 생성]
	position:0, 	limit:7, 	capacity:7
[2바이트 저장후]
	position:2, 	limit:7, 	capacity:7
[3바이트 저장후]
	position:5, 	limit:7, 	capacity:7
[flip() 실행후]
	position:0, 	limit:5, 	capacity:7
[3바이트 읽은후]
	position:3, 	limit:5, 	capacity:7
[---현재 위치를 마크 해놓음---]
[2바이트 읽은후]
	position:5, 	limit:5, 	capacity:7
[---position을 마크 위치로 옮김---]
	position:3, 	limit:5, 	capacity:7
[rewind() 실행후
	position:0, 	limit:5, 	capacity:7
[clear() 실행후
	position:0, 	limit:7, 	capacity:7



 

-Buffer의 변환

ByteBuffer에서 String으로 변환될 때쓰는 메소드가 있다.

일단 문자열을 ByteBuffer로 변환하려면 encode()

ByteBuffer을 문자열로 변환하려면 decode() 메소드를 사용한다.

 

ㅇ파일채널

파일채널 java.nio.channels.FileChannel을 이용하면 파일 읽기과 쓰기를 할 수 있다.

package SystemEx01;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class FileChannelEx01 {

	public static void main(String[] args) {
		Path srcFile = Paths.get("./channel.txt");
		Charset utf8 = Charset.forName("utf-8");
		FileChannel writeChannel = null;
		
		try {
			//파일 생성
			writeChannel = FileChannel.open(
					srcFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
			String msg = "hello FileChannel";
			ByteBuffer buffer = utf8.encode(msg);
			int bCount = writeChannel.write(buffer);
			
			System.out.println("출력완료");
			
			//파일 출력
			Path path2 = Paths.get("./channel.txt");
			FileChannel fileChannel = FileChannel.open(path2, StandardOpenOption.READ);
			
			ByteBuffer byteBuffer = ByteBuffer.allocate(100);
			Charset charset = Charset.defaultCharset();
			String data = "";
			int byteCount;
			
			while(true) {
				byteCount = fileChannel.read(byteBuffer);
				if(byteCount == -1) {System.out.println("완료"); break;}
				byteBuffer.flip();
				data += charset.decode(byteBuffer).toString();
				byteBuffer.clear();
			}
			System.out.println("file.txt: " + data);
			
		} catch(java.nio.channels.NonReadableChannelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if( writeChannel != null) try {writeChannel.close();} catch(IOException e) {}
		}

	}

}


출력완료
완료
file.txt: hello FileChannel

 

ㅇ파일복사

1140

파일복사를 구현하기 위해서는 하나의 ByteBuffer 를 사이에 두고, 파일 읽기용 FileChannel과

파일 쓰기용 FileChannel이 읽기와 쓰기를 교대로 번갈아 수행하도록 하면된다.

package SystemEx01;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class FileCopyExample {

	public static void main(String[] args) throws IOException {
		Path from = Paths.get("./earth.jpg");
		Path to = Paths.get("./earth2.jpg");
		
		FileChannel fileChannel_from = FileChannel.open(
				from, StandardOpenOption.READ);
		
		FileChannel fileChannel_to = FileChannel.open(
				to, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
		
		ByteBuffer buffer = ByteBuffer.allocateDirect(100);
		int byteCount;
		while(true) {
			buffer.clear();
			byteCount = fileChannel_from.read(buffer);	//읽기
			if( byteCount == -1 ) break;
			buffer.flip();
			fileChannel_to.write(buffer);	//쓰기
		}
		
		fileChannel_from.close();
		fileChannel_to.close();
		System.out.println("파일 복사 성공");
	}
}



파일 복사 성공

 

 

 

 

앞으로 배울 내용

기본적인 파일 이외의 특수 파일

*아래 파일들을 조작하려면 외부(또는 제작업체)에서 제공하는 API가 필요하다.
1. office 파일
	excel, word
2. 한글 파일
	등등
	

excel 파일 경우
	csv - , 구분자로 사용한다.
	xls - 특수형식
	
마이크로소프트에서 만든 파일에 접근할 수 있는 API제공하는 곳
Apache POI
	https://poi.apache.org/
	
엑셀데이터만 접근할 수 있는 곳
JXL
	http://jexcelapi.sourceforge.net/
	-> menu에 Files -> jexcelapi -> 2.6.12
	jexcelapi_2_6_12.zip 는 윈도우용
	jexcelapi_2_6_12.tar.gz 는 유닉스용
	
	다운받은다음 압축을 풀면 jxl.jar 이 파일이 라이브러리이다.
	보통 외부에서 주는 API는 .jar 형태이다. (자바 아카이브)
	
	자바 워크스페이스에 APIs 폴더를 만들고 jxl.jar 파일을 복사한다.

 

이제 이클립스에서 jxl.jar파일을 가져오자.

먼저 새로운 자바프로젝트를 만들고 아래처럼 next를 누른다. 다음 라이브러리에서 외부 라이브러리 파일 불러오기를 클릭한다.

그런 다음 아래 파일을 ExcelEx 자바 프로젝트에 복사해서 집어넣는다.

zipcode_seoul_euckr_type2.xls
2.29MB

 

 

 

그러면 아래와 같이 자바프로젝트 내에 엑셀 파일이 생긴다. 이때 .xls 파일이어야 한다.

 

이때 module 에 requires jxl; 을 써주어야 한다.

module ExcelEx {
	requires java.se;
	requires jxl;
}

 

이제 엑셀데이터의 행의 수와 열의 수를 가져와보자.

package ExcelEx01;

import java.io.File;
import java.io.IOException;

import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;

public class ExcelEx01 {

	public static void main(String[] args) {
		Workbook workbook = null;
		
		try {
			workbook = Workbook.getWorkbook(new File("./zipcode_seoul_euckr_type2.xls"));
			Sheet sheet = workbook.getSheet(0);
			
			System.out.println(sheet.getRows());
			System.out.println(sheet.getColumns());
		} catch (BiffException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IndexOutOfBoundsException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if( workbook != null) workbook.close();
		}
	}
}

18308
7

 

이제 데이터의 참조위치와 데이터 값을 가져와보자.

Cell zipcode = sheet.getCell(0, 0);
System.out.println(zipcode);
System.out.println(zipcode.getContents());

Cell zipcode = sheet.getCell(1, 0);
System.out.println(zipcode);
System.out.println(zipcode.getContents());

Cell zipcode = sheet.getCell(0, 1);
System.out.println(zipcode);
System.out.println(zipcode.getContents());

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
jxl.read.biff.LabelSSTRecord@6b57696f
135-806

jxl.read.biff.LabelSSTRecord@6b57696f
서울

jxl.read.biff.LabelSSTRecord@6b57696f
135-807


셀 데이터는 (열, 행)으로 가져온다.

 

이제 한 줄의 데이터를 가져와본다.

			Cell zipcode = sheet.getCell(0, 0);
			Cell sido = sheet.getCell(1, 0);
			Cell gugun = sheet.getCell(2, 0);
			Cell dong = sheet.getCell(3, 0);
			Cell ri = sheet.getCell(4, 0);
			Cell bunji = sheet.getCell(5, 0);
			
			System.out.println(zipcode.getContents());
			System.out.println(sido.getContents());
			System.out.println(gugun.getContents());
			System.out.println(dong.getContents());
			System.out.println(ri.getContents());
		        System.out.println(bunji.getContents());
            
            
            
            ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
135-806
서울
강남구
개포1동
경남아파트

 

-문제: excel 패키지를 이용해서 동이름을 검색하면 해당 동을 포함하는 모든 주소 출력하기

끝 을 입력하면 프로그램 종료시키기

package ExcelEx01;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;

public class ExcelZipcodeEx01 {

	public static void main(String[] args) {
		BufferedReader br = null;
		Workbook workbook = null;
		
		try {
			br = new BufferedReader(new java.io.InputStreamReader(System.in));
			workbook = Workbook.getWorkbook(new File("./zipcode_seoul_euckr_type2.xls"));
			Sheet sheet = workbook.getSheet(0);
			
			while(true) {
				//입력값 검사
				System.out.print("데이터 입력: ");
				String data = br.readLine();
				if (data.equals("끝")) { break; }
					
				//데이터 출력	
				for(int i=0; i<sheet.getRows(); i++) {
					Cell dong = sheet.getCell(3,i);
					if( dong.getContents().contains(data) ) {
						for(int j=0; j<sheet.getColumns(); j++) {
							System.out.print(sheet.getCell(j,i).getContents()+" ");
						}
						System.out.println();
					}
				}
			}
			System.out.println("프로그램 종료");
		} catch (BiffException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IndexOutOfBoundsException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(br != null) try {br.close();} catch(IOException e) {}
			if(workbook != null) workbook.close();
		}
	}
}





데이터 입력: 개포
135-806 서울 강남구 개포1동 경남아파트  1 
135-807 서울 강남구 개포1동 우성3차아파트 (1∼6동) 2 
135-806 서울 강남구 개포1동 우성9차아파트 (901∼902동) 3 
135-770 서울 강남구 개포1동 주공아파트 (1∼16동) 4 
135-805 서울 강남구 개포1동 주공아파트 (17∼40동) 5 

데이터 입력: 반포
137-761 서울 서초구 반포1동 반포리체아파트 (101∼109동) 4583 
137-930 서울 서초구 반포1동 반포자이아파트 (101∼144동) 4584 
137-933 서울 서초구 반포1동 삼호가든아파트 (A∼F동) 4585 
137-932 서울 서초구 반포1동 삼호가든아파트 (가∼마동) 4586 
137-931 서울 서초구 반포1동 삼호가든아파트 (501∼503동) 4587 
137-809 서울 서초구 반포1동  716∼729 4590 

데이터 입력: 끝
프로그램 종료

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

728x90
반응형
Comments