배운것
자바 입출력에 대한 개략적인 이해
내용 정리
스트림 (InputStream / OutputStream)
- 데이터를 운반하는데 사용되는 연결 통로
- 자바에서 입출력을 수행하기 위해 필요
- 단방향 통신
- 입력/출력을 동시에 수행하려면 입력스트림, 출력스트림, 2개의 스트림 필요
- 바이트단위로 데이터 전송
입력스트림 | 출력스트림 | 입출력 대상의 종류 |
FileInputStream | FileOutputStream | 파일 |
ByteArrayInputStream | ByteArrayOutputStream | 메모리(byte배열) |
PipedInputStream | PipedOutputStream | 프로세스(프로세스간 통신) |
AudioInputStream | AudioOutputStream | 오디오장치 |
자바에서는 입출력을 처리할 수 있는 표준화된 방법을 제공
-> 입출력의 대상이 달라져도 동일한 방법으로 입출력이 가능! ( 프로그래밍 하기 편리하다는 장점 )
보조스트림
- 실제 데이터를 주고받는 스트림이 아니라 데이터를 직접 입출력 할 수 없음
- 스트림의 기능을 향상시키거나 새로운 기능을 추가하는 용도
- 기반스트림 생성 -> 기반스트림을 이용해서 보조스트림 생성
스트림을 이용해 작업을 한 후에는 close()를 호출해 반드시 닫아주자
문자기반 스트림 (Reader / Writer)
- 문자데이터를 입출력할 때 사용
- 바이트기반 스트림과 이름만 조금 다를 뿐 활용방법은 거의 같다
자주 쓰이는 스트림들
FileInputStream/FileOutputStream
- 파일에 입출력을 하기 위한 스트림
public class FileCopy {
public static void main(String[] args) throws IOException {
// FileInputStream, FileOutputStream 생성
// args[0]파일을 읽어서 args[1]에 저장
FileInputStream fis = new FileInputStream(args[0]);
FileOutputStream fos = new FileOutputStream(args[1]);
int data = 0;
// fis의 내용을 읽어서 fos로 저장
while((data=fis.read())!=-1) {
fos.write(data);
}
fis.close();
fos.close();
}
}
BufferedInputStream/BufferedOutputStream
- 스트림의 입출력 효율을 높이는 용도, 대부분의 입출력 작업에 사용
- 데이터를 버퍼크기만큼 가져와 저장, 입출력
public class Ex15_6 {
public static void main(String[] args) {
// 버퍼를 이용해 123456789가 담긴 123.txt를 생성
try {
// 기반스트림(보조스트림)
FileOutputStream fos = new FileOutputStream("100.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos,5);
for(int i='1'; i<'9'; i++) {
bos.write(i);
}
// 버퍼에 남아있는 모든 데이터를 출력소스에 출력
// 보조스트림의 close()만 호출하면 됨
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
기반스트림(FileOutputStream)을 이용해 보조스트림(BufferedOutputStream)을 생성
SequenceInputStream
- 여러 개의 입력스트림을 연속적으로 연결해서 처리
public class Ex15_7 {
public static void main(String[] args) {
byte[] arr1 = {0,1,2};
byte[] arr2 = {3,4,5};
byte[] arr3 = {6,7,8};
byte[] outSrc = null;
Vector v = new Vector();
v.add(new ByteArrayInputStream(arr1));
v.add(new ByteArrayInputStream(arr2));
v.add(new ByteArrayInputStream(arr3));
// 여러 inputStream을 하나로 연결
SequenceInputStream input = new SequenceInputStream(v.elements());
ByteArrayOutputStream output = new ByteArrayOutputStream();
int data=0;
try {
while((data=input.read())!=-1) {
output.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
outSrc = output.toByteArray();
System.out.println(Arrays.toString(outSrc));
}
}
FileReader/FileWriter
- 파일로부터 텍스트 데이터를 읽고, 파일에 쓰는데 사용
- 사용 방법은 FileInputStream/FileOutputStream과 같음
public class Ex15_9 {
public static void main(String[] args) {
try {
FileReader fr = new FileReader(args[0]);
FileWriter fw = new FileWriter(args[1]);
int data = 0;
while((data=fr.read())!=-1) {
if(data!='\t' && data!='\n' && data!=' ' && data!='\r')
fw.write(data);
}
fr.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader/BufferedWriter
- 버퍼를 이용해서 입출력의 효율을 높일 수 있도록 해주는 역할
- 문자 기반
public class Ex15_11 {
public static void main(String[] args) {
// 버퍼를 이용해 파일을 읽어 들임
try {
FileReader fr = new FileReader("Ex15_11.java");
BufferedReader br = new BufferedReader(fr);
String line = "";
for(int i=1; (line = br.readLine())!=null; i++) {
if(line.indexOf(';')!=-1)
System.out.println(i+":"+line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
위의 스트림 사용예제와는 다르게, readLilne()을 이용해서 라인단위로 읽어들이임
때문에 위에서 사용했던 방법인 int data를 선언 후 한문자씩 읽어 들이는 것이 아니라, String line을 선언 후, 문장단위로 읽어 들임
InputStreamReader/OutputStreamWriter
- 바이트기반 스트림을 문자기반 스트림으로 연결시켜주는 역할
- 바이트기반 스트림의 데이터를 지정된 인코딩의 문자데이터로 변환하는 작업을 수행
public class Ex15_12 {
public static void main(String[] args) {
String line = "";
try {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
System.out.println("사용중인 os 인코딩:"+isr.getEncoding());
do {
System.out.print("문장을 입력하세요 (q:종료)");
line = br.readLine();
System.out.println("입력한 문장:"+line);
} while(!line.equalsIgnoreCase("q"));
// System.in과 같은 표준입출력은 닫지 않아도 됨
// br.close();
System.out.println("프로그램 종료");
} catch (Exception e) {
e.printStackTrace();
}
}
}
File
- 가장 많이 사용되는 입출력 대상
- File클래스를 통해서 파일과 디렉토리를 다룰 수 있음
- File인스턴스는 파일 일 수도 있고, 디렉토리일 수도 있다
public class Ex15_15 {
public static void main(String[] args) throws IOException {
File f = new File("C:\\BIBLE JAVA2\\CH15\\src\\Ex15_15.java");
String fileName = f.getName();
int pos = fileName.lastIndexOf('.');
// 파일 이름
System.out.println(f.getName());
// 확장자 뺀 파일이름
System.out.println(fileName.substring(0,pos));
// 확장자
System.out.println(fileName.substring(pos+1));
// 경로
System.out.println(f.getPath());
// 절대경로
System.out.println(f.getAbsolutePath());
// 정규경로
System.out.println(f.getCanonicalPath());
// 파일이 속해있는 디렉토리
System.out.println(f.getParent());
// 경로구분자
System.out.println(File.pathSeparator);
// 경로구분자
System.out.println(File.pathSeparatorChar);
// 이름구분자
System.out.println(File.separator);
// 이름구분자`
System.out.println(File.separatorChar);
System.out.println(System.getProperty("user.dir"));
}
}
File인스턴스를 생성하고 메소드를 이용해서 파일의 경로와 구분자 등의 정보를 얻을 수 있음
user.dir는 현재 프로그램이 실행 중인 디렉토리를 의미함
public class Ex15_16 {
public static void main(String[] args) {
if(args.length!=1) {
System.out.println("USAGE : java Ex15_16 DIRECTORY");
System.exit(0);
}
File f = new File(args[0]);
if(!f.exists() || !f.isDirectory()) {
System.out.println("유효하지 않은 디렉토리입니다.");
System.exit(0);
}
File[] files = f.listFiles();
for(int i=0; i<files.length; i++) {
String fileName = files[i].getName();
System.out.println(files[i].isDirectory() ? "["+fileName+"]" : fileName);
}
}
}
File인스턴스를 이용해 파일과 디렉토리를 구별하는 예제
표준 입출력
- 콘솔창을 통한 데이터 입력과 데이터 출력을 의미
- 3가지 입출력 스트림 (System.in, System.out, System.err)
- 별도로 스트림 생성하지 않고 사용 가능
public class Ex15_13 {
public static void main(String[] args) {
System.out.println("out : Hello World!");
System.err.println("err : Hello World!");
}
}
직렬화
- 객체를 데이터 스트림으로 만드는 것
- 객체에 저장된 데이터를 스트림에 쓰기(write)위해 연속적인 데이터로 변환하는 것
- ObjectOutputStream 사용
- 보조 스트림
직렬화가 가능한 클래스를 만들기 위해서는,
직렬화하고자 하는 클래스가 java.io.Serrializable인터페이스를 구현하면 됨
tarnsnt를 붙여서 직렬화 대상에서 제외하도록 할 수 있음
public class UserInfo implements Serializable {
String name;
transient String password; // 직렬화 대상에서 제외
int age;
역직렬화
- 스트림으로부터 데이터를 읽어서 객체를 만드는 것
- ObjectInputStream 사용
- 보조 스트림
직렬화/역직렬화 예시
public class Ex15_20 {
public static void main(String[] args) {
try {
// 저장할 파일 이름
String fileName = "UserInfo.ser";
// 파일에 저장
// 기반스트림 FileOutputStream, 보조스트림 BufferedOutputStream, ObjectOutputStream
FileOutputStream fos = new FileOutputStream(fileName);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 직렬화하기위한 스트림 생성
ObjectOutputStream oos = new ObjectOutputStream(bos);
// 직렬화할 객체 생성
UserInfo u1 = new UserInfo("롭 홀딩", "kkkdg", 26);
UserInfo u2 = new UserInfo("외데고르", "rhw125", 24);
// 직렬화할 객체를 담을 리스트 생성
ArrayList<UserInfo> list = new ArrayList<>();
list.add(u1);
list.add(u2);
// 객체 직렬화
oos.writeObject(u1);
oos.writeObject(u2);
oos.writeObject(list);
oos.close();
System.out.println("직렬화 종료");
} catch (IOException e) {
e.printStackTrace();
}
}
}
직렬화
public class Ex15_21 {
public static void main(String[] args) {
try {
// 읽어올 파일의 이름
String fileName = "UserInfo.ser";
// 파일을 읽어옮
// 기반 스트림 FileInputStream, 보조스트림 BufferedInputStream, ObjectInputStream
FileInputStream fis = new FileInputStream(fileName);
BufferedInputStream bis = new BufferedInputStream(fis);
// 역직렬화하기 위한 ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(bis);
// 역직렬화, 객체를 읽어옮
// 객체를 읽어올 때, 출력한 순서와 일치해야함
UserInfo u1 = (UserInfo) ois.readObject();
UserInfo u2 = (UserInfo) ois.readObject();
ArrayList<UserInfo> list = (ArrayList<UserInfo>) ois.readObject();
// 역직렬화한 객체들을 출력
System.out.println(u1);
System.out.println(u2);
System.out.println(list.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
역직렬화
느낀점 / 보완할 점
자주 사용해보지 않은 부분이라 그런지 낯선 부분들이 있었다.
개념들만 이해하려 하지 말고 어떻게 사용하는지등 손으로 직접 쳐보며 익혀야겠다.
혹시 잘못된 정보가 있다면 지적 부탁드려요.
'아카이브 > 자바의 정석' 카테고리의 다른 글
자바의 정석 2장 변수 (0) | 2021.12.27 |
---|---|
자바의 정석 16장 네트워킹 (0) | 2021.12.24 |
13장 쓰레드 20200106 (0) | 2021.01.06 |
13장 쓰레드 20210104 (0) | 2021.01.04 |
13장 Thread 20201120 (0) | 2020.11.20 |