1. 입출력(I/O)이란?
- 입력(Input)과 출력(Output)을 줄여 부르는 말
- 두 대상 간의 데이터를 주고 받는 것
2. 스트림(stream)이란?
- 데이터를 운반(입출력)하는데 사용되는 연결 통로
- 하나의 스트림으로 입출력을동시에 수행할 수 없다. (단방향 통신)
- 입출력을 동시에 수행하려면 2개의 스트림이 필요하다.
- 바이트 기반 스트림(기본) : 데이터를 바이트 단위로 주고 받는다.
- 보조 스트림 : 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해 사용한다.
독립적으로 입출력을 수행할 수 없다.
- 문자 기반 스트림 : 입출력 단위가 문자(char, 2 byte)인 스트림
문자기반 스트림의 최고 조상이다.
🌳 바이트 기반 스트림 실습 1 (1byte 씩 가져오기)
public class ByteArrayIOTest01 {
public static void main(String[] args) {
byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] outSrc = null;
// 1. 스트림 객체 생성
ByteArrayInputStream input = new ByteArrayInputStream(inSrc);
ByteArrayOutputStream output = new ByteArrayOutputStream();
// 2. 입력용 스트림으로 데이터를 읽어와 출력용 스트림으로 출력하기
int data; // 읽어온 데이터가 저장될 변수 선언
// read() 메소드 => 더 이상 읽어올 데이터가 없으면 -1을 반환한다.
while ((data = input.read()) != -1) {
output.write(data); // 읽어온 데이터 출력하기
}
// 3. 출력된 스트림값을 배열로 변환하기
outSrc = output.toByteArray();
// 4. 입출력 작업을 모두 마치면 사용한 스트림을 닫아준다.
// => 자원 반납
try {
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(" inSrc => " + Arrays.toString(inSrc));
System.out.println(" outSrc => " + Arrays.toString(outSrc));
}
}
// 실행 결과
// inSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// outSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
🌳 바이트 기반 스트림 실습 2-1 (배열으로 가져오기)
public class ByteArrayIOTest02 {
public static void main(String[] args) {
byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] outSrc = null;
byte[] temp = new byte[4]; // 입력용 스트림에 사용할 배열
// 1. 스트림 객체 생성
ByteArrayInputStream input = new ByteArrayInputStream(inSrc);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
// 읽어올 데이터 존재 유무 확인 (0보다 크면 데이터 있음)
while (input.available() > 0) {
input.read(temp);
output.write(temp);
System.out.println("반복문 안에서 temp : " + Arrays.toString(temp));
}
outSrc = output.toByteArray();
System.out.println();
System.out.println(" inSrc => " + Arrays.toString(inSrc));
System.out.println(" outSrc => " + Arrays.toString(outSrc));
input.close();
output.close();
} catch (IOException e) {
}
}
}
// 실행 결과
// 반복문 안에서 temp : [0, 1, 2, 3]
// 반복문 안에서 temp : [4, 5, 6, 7]
// 반복문 안에서 temp : [8, 9, 6, 7]
// inSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// outSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 7]
- 입출력 결과가 다른 이유는?
temp 배열의 크기는 4인데, 0123 / 4567 을 읽은 후 남은 데이터는 2개 뿐이다.
따라서 앞의 4, 5만 8, 9로 대체되고, 뒤의 6, 7은 그대로 출력된 것이다.
이때 int read(byte[] b, int off, int len) 메소드를 사용한다.
🌳 바이트 기반 스트림 실습 2-2 (배열으로 가져오기) : read(byte[] b, int off, int len) 사용
public class ByteArrayIOTest02 {
public static void main(String[] args) {
byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] outSrc = null;
byte[] temp = new byte[4]; // 입력용 스트림에 사용할 배열
// 1. 스트림 객체 생성
ByteArrayInputStream input = new ByteArrayInputStream(inSrc);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
// 읽어올 데이터 존재 유무 확인 (0보다 크면 데이터 있음)
while (input.available() > 0) {
// input.read(temp);
// output.write(temp);
// System.out.println("반복문 안에서 temp : " + Arrays.toString(temp));
int len = input.read(temp); // 실제 읽어온 데이터 수를 반환한다.
// temp 배열의 내용 중 0번째부터 len의 개수만큼 출력한다.
output.write(temp, 0, len);
}
outSrc = output.toByteArray();
System.out.println();
System.out.println(" inSrc => " + Arrays.toString(inSrc));
System.out.println(" outSrc => " + Arrays.toString(outSrc));
input.close();
output.close();
} catch (IOException e) {
}
}
}
// inSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// outSrc => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
🌳 바이트 기반의 스트림을 이용하여 파일 내용 읽어오기
- File 객체를 생성했다고 해서 파일이나 디렉토리가 생기지 않는다.
File 객체를 생성한 후에는 해당 경로에 실제 파일이 존재하는지 확인해주는 작업이 필요하다.
그래서 이 메소드의 리턴 값이 false일 때, 파일이나 디렉토리를 생성할 수 있다. (exist() 메소드 이용)
public class FileIOTest01 {
public static void main(String[] args) {
// 바이트 기반의 스트림을 이용하여 파일 내용 읽어오기
// => FileInputStream을 이용한다.
try {
// 파일 입력용 스트림 객체 생성
// 방법 1. 읽어올 파일명과 경로를 문자열로 지정한다.
// FileInputStream fin = new FileInputStream("d:/d_other/test.txt");
// 방법 2. 읽어올 파일 정보가 저장될 File 객체를 이용한다.
File file = new File("d:/d_other/test.txt");
FileInputStream fin = new FileInputStream(file);
int c; // 읽어온 데이터가 저장될 변수
while ((c = fin.read()) != -1) {
// 읽어온 데이터를 화면에 출력하기
System.out.print((char) c); // char로 형변환 하지 않을 경우 숫자코드값이 출력된다.
}
fin.close(); // 작업 완료 후 스트림 닫기(자원 반납)
} catch (IOException e) {
}
}
}
// 파일 내용
// abcdefg
// ABCDEFG
// 1234567890
// !@#$%^&*()_+
// 실행 결과
// abcdefg
// ABCDEFG
// 1234567890
// !@#$%^&*()_+
- 바이트 기반의 스트림을 이용하였을 때
txt 파일에 한글(영어권이 아닌 문자)이 포함되어 있다면 코드값을 1byte로 표현하지 못하기 때문에
한글 부분이 깨져서 나온다.
🌳 바이트 기반의 스트림을 이용하여 파일에 출력(저장)하기
public class FileIOTest02 {
public static void main(String[] args) {
// 바이트 기반 스트림을 이용하여 파일에 출력하기
try {
// 파일 출력용 스트림 객체 생성
// 읽어올 파일명과 경로를 문자열로 지정한다.
FileOutputStream fos = new FileOutputStream("d:/d_other/out.txt");
System.out.println("출력 작업 시작"); // 확인용
for (char ch = 'A'; ch <= 'Z'; ch++) {
fos.write(ch); // ch 변수의 데이터를 파일로 출력한다.
if ((ch - 64) % 6 == 0) { // 한 줄에 여섯 개씩 출력되게 하기 위해서
fos.write('\n');
}
}
System.out.println("출력 작업 완료");
fos.close(); // 쓰기 작업 완료 후 스트림 닫기(자원 반납)
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 실행 결과
// 출력 작업 시작
// 출력 작업 완료
// 생성된 txt 파일
// ABCDEF
// GHIJKL
// MNOPQR
// STUVWX
// YZ
🌳 #바이트 기반의 스트림을 이용하여 파일에 출력(저장)하기#에서 저장한 파일 읽어와 화면에 출력하기
public class FileIOTest02 {
public static void main(String[] args) {
// 바이트 기반 스트림을 이용하여 파일에 출력하기
try {
// 파일 출력용 스트림 객체 생성
// 읽어올 파일명과 경로를 문자열로 지정한다.
FileOutputStream fos = new FileOutputStream("d:/d_other/out.txt");
System.out.println("출력 작업 시작"); // 확인용
for (char ch = 'A'; ch <= 'Z'; ch++) {
fos.write(ch); // ch 변수의 데이터를 파일로 출력한다.
if ((ch - 64) % 6 == 0) { // 한 줄에 여섯 개씩 출력되게 하기 위해서
fos.write('\n');
}
}
System.out.println("출력 작업 완료\n");
fos.close(); // 쓰기 작업 완료 후 스트림 닫기(자원 반납)
// ==============================================================
// 위에서 저장한 파일을 읽어와 화면에 출력하기
FileInputStream fin = new FileInputStream("d:/d_other/out.txt");
int fileInput;
while ((fileInput = fin.read()) != -1) {
System.out.print((char) fileInput);
}
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 실행 결과
// 출력 작업 시작
// 출력 작업 완료
// ABCDEF
// GHIJKL
// MNOPQR
// STUVWX
// YZ
🌳 문자 기반 스트림 실습1 (문자 기반의 스트림을 이용하여 파일 내용 읽어오기)
public class FileIOTest03 {
public static void main(String[] args) {
// 문자 기반의 스트림을 이용하여 파일 내용 읽어오기
// 파일 입력용 스트림 객체 생성
try {
FileReader fr = new FileReader("d:/d_other/test.txt");
int c; // 읽어온 데이터를 저장할 변수
while ( (c = fr.read()) != -1) {
System.out.print((char)c);
}
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 실행 결과
// abcdefg
// ABCDEFG
// 1234567890
// !@#$%^&*()_+
- 문자 기반의 스트림을 이용하였을 때는 한글이 깨지지 않고 잘 나오게 된다.
🌳 문자 기반 스트림 실습2 (사용자가 입력한 내용을 그대로 파일로 저장하기)
System.in, System.out => 콘솔(표준입출력장치)
System.in(입력용 => 키보드), System.out(출력용 => 화면)
바이트 기반의 스트림을 문자 기반의 스트림으로 변환해주는 스트림
=> InputStreamReader (입력용)
=> OutPutStreamWriter (출력용)
public class FileIOTest04 {
public static void main(String[] args) {
try {
// 사용자가 입력한 내용을 그대로 파일로 저장하기 => 문자 기반 스트림 이용
// System.in, System.out => 콘솔(표준입출력장치)
// System.in(입력용 => 키보드), System.out(출력용 => 화면)
// 바이트 기반의 스트림을 문자 기반의 스트림으로 변환해주는 스트림
// => InputStreamReader (입력용)
// => OutPutStreamWriter (출력용)
InputStreamReader isr = new InputStreamReader(System.in);
// 해당 경로에 파일이 없을 경우 새로 생성하고, 있으면 덮어쓴다.
FileWriter fw = new FileWriter("d:/d_other/testChar.txt");
System.out.println("내용을 입력하세요. (입력의 끝은 Ctrl + Z 입니다.)");
int c;
while ((c = isr.read()) != -1) {
fw.write(c); // 콘솔로 입력받은 데이터를 파일에 출력한다.
}
isr.close();
fw.close();
} catch (Exception e) {
}
}
}
🌳 한글이 저장된 파일 읽어오기 (utf8)
public class FileIOTest05 {
public static void main(String[] args) {
/*
* 한글이 저장된 파일 읽어오기 (문자 기반 스트림 이용)
*/
try {
FileReader fr = new FileReader("d:/d_other/test_utf8.txt");
int c;
while ((c = fr.read()) != -1) {
System.out.print((char) c);
}
fr.close();
} catch (IOException e) {
}
}
}
// 실행 결과
// utf-8파일 내용
// 이 문서는 utf-8인코딩 방식의
// 파일 내용입니다.
🌳 한글이 저장된 파일 읽어오기 (ansi)
public class FileIOTest05 {
public static void main(String[] args) {
/*
* 한글이 저장된 파일 읽어오기 (문자 기반 스트림 이용)
* => 인코딩 방식을 지정해서 읽어오기
* => InputStreamReader를 이용해서 작업한다.
*/
try {
FileReader fr = new FileReader("d:/d_other/test_ansi.txt");
int c;
while ((c = fr.read()) != -1) {
System.out.print((char) c);
}
fr.close();
} catch (IOException e) {
}
}
}
// Ansi���� ����
// �� ������ ANSI(MS949)���ڵ� �����
// ���� �����Դϴ�.
- ansi인코딩 방식의 파일은 읽어오지 못 함
그러면 ansi인코딩 방식의 파일을 읽어오는 방법은?
🌳 한글이 저장된 파일 읽어오기 (ansi)
기본 인코딩 방식이 아닌 인코딩 방식을 지정하여 사용하기
인코딩 방식 예시
- MS949 => 윈도우의 기본 한글 인코딩 방식(ANSI 방식과 같다.)
- UTF-8 => 유니코드 UTF-8 인코딩 방식
- US-ASCII => 영문 전용 인코딩 방식
public class FileIOTest05 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("d:/d_other/test_ansi.txt");
// 기본 인코딩 방식으로 읽어온다.
// InputStreamReader isr = new InputStreamReader(fis);
// 기본 인코딩 방식이 아닌 인코딩 방식을 지정하여 사용하기
InputStreamReader isr = new InputStreamReader(fis, "ms949");
// InputStreamReader isr = new InputStreamReader(fis, "utf-8");
int c;
while ((c = isr.read()) != -1) {
System.out.print((char) c);
}
// fis.close();
isr.close(); // 보조 스트림을 닫으면 같이 사용된 기반이 되는 스트림도 자동으로 닫힌다.
} catch (IOException e) {
}
}
}
🌳 d드라이브의 d_other 폴더에 있는 '스폰지밥.png' 파일을
d드라이브의 d_other 폴더의 하위 폴더 중에서 '연습용' 폴더에
'스폰지밥_복사본.png' 파일로 복사하는 프로그램을 작성하시오.
방법 1.
public class FileCopy {
public static void main(String[] args) throws IOException {
File file = new File("D:\\D_Other\\스폰지밥.png");
File newFile = new File("D:\\D_Other\\연습용\\스폰지밥_복사본.png");
if (!file.exists()) {
System.out.println("원본 파일이 없습니다.");
System.out.println("복사 작업을 중지합니다.");
return;
}
FileInputStream input = new FileInputStream(file);
FileOutputStream output = new FileOutputStream(newFile);
byte[] buf = new byte[1024];
int readData;
while ((readData = input.read(buf)) > 0) {
output.write(buf, 0, readData);
}
input.close();
output.close();
}
}
방법 2.
public class FileCopy {
public static void main(String[] args) throws IOException {
File file = new File("d:/d_other/풍경.jpg");
File newFile = new File("d:/d_other/연습용/풍경_복사본.jpg");
if (!file.exists()) {
System.out.println("원본 파일이 없습니다.");
System.out.println("복사 작업을 중지합니다.");
return;
}
FileInputStream input = new FileInputStream(file);
FileOutputStream output = new FileOutputStream(newFile);
System.out.println("복사 시작");
int data;
while ((data = input.read()) > -1) {
output.write(data);
}
System.out.println("복사 완료");
input.close(); // try catch문을 사용한다면 close는 finally에 작성하는 것이 좋음
output.close();
}
}
🌳 SWING의 파일 열기, 저장 창 연습
public class FileCopy {
File selectedFile = null;
public static void main(String[] args) throws IOException {
new FileCopy().fileCopyStart();
}
public void fileCopyStart() throws IOException {
// File file = new File("d:/d_other/풍경.jpg");
File file = openDialog();
// File newFile = new File("d:/d_other/연습용/풍경_복사본.jpg");
if (file == null || !file.exists()) {
System.out.println("원본 파일이 없습니다.");
System.out.println("복사 작업을 중지합니다.");
return;
}
// 대상 파일 선택
File targetFile = saveDialog();
if (targetFile == null) {
System.out.println("대상 파일을 선택하지 않았습니다.");
System.out.println("복사 작업을 중지합니다.");
return;
}
FileInputStream input = new FileInputStream(file);
// FileOutputStream output = new FileOutputStream(newFile);
FileOutputStream output = new FileOutputStream(targetFile);
System.out.println("복사 시작");
int data;
while ((data = input.read()) > -1) {
output.write(data);
}
System.out.println("복사 완료");
input.close(); // try catch문을 사용한다면 close는 finally에 작성하는 것이 좋음
output.close();
}
// 열기용 창을 보여주고 선택한 파일을 반환하는 메소드
private File openDialog() {
// SWING의 파일 열기, 저장 창 연습
JFileChooser chooser = new JFileChooser();
// 보여줄 파일의 확장자 설정
FileNameExtensionFilter img = new FileNameExtensionFilter("Image File",
new String[] { "png", "jpg", "jpeg", "gif" });
FileNameExtensionFilter txt = new FileNameExtensionFilter("Text File", "txt");
FileNameExtensionFilter doc = new FileNameExtensionFilter("Ms-Word 문서", "docx", "doc");
chooser.addChoosableFileFilter(img);
chooser.addChoosableFileFilter(txt);
chooser.addChoosableFileFilter(doc);
// 확장자 목록 중에 기본적으로 선택될 확장자 지정
chooser.setFileFilter(txt);
// 전체 파일 목록 (*.*) 표시 여부 설정 (true: 설정, false: 해제)
chooser.setAcceptAllFileFilterUsed(true);
// Dialog 창에 나타날 기본 경로 설정
chooser.setCurrentDirectory(new File("d:/d_other"));
// 파일 선택만 도와주고 파일을 실제로 열거나 저장하진 않음
// 열기용 창
int result = chooser.showOpenDialog(new Panel());
// 저장용 창
// int result = chooser.showSaveDialog(new Panel());
// '저장' 또는 '열기' 버튼을 눌렀을 경우
if (result == JFileChooser.APPROVE_OPTION) {
// 선택한 파일 객체 구하기
selectedFile = chooser.getSelectedFile();
// System.out.println("선택한 파일 : " + selectedFile.getAbsolutePath());
// 선택한 파일 정보를 이용해서 실제 읽기 또는 쓰기 작업을 수행
}
return selectedFile;
}
// 저장용 창을 보여주고 선택한 파일을 반환하는 메소드
private File saveDialog() {
// SWING의 파일 열기, 저장 창 연습
JFileChooser chooser = new JFileChooser();
// 보여줄 파일의 확장자 설정
FileNameExtensionFilter img = new FileNameExtensionFilter("Image File",
new String[] { "png", "jpg", "jpeg", "gif" });
FileNameExtensionFilter txt = new FileNameExtensionFilter("Text File", "txt");
FileNameExtensionFilter doc = new FileNameExtensionFilter("Ms-Word 문서", "docx", "doc");
chooser.addChoosableFileFilter(img);
chooser.addChoosableFileFilter(txt);
chooser.addChoosableFileFilter(doc);
// 확장자 목록 중에 기본적으로 선택될 확장자 지정
chooser.setFileFilter(txt);
// 전체 파일 목록 (*.*) 표시 여부 설정 (true: 설정, false: 해제)
chooser.setAcceptAllFileFilterUsed(true);
// Dialog 창에 나타날 기본 경로 설정
chooser.setCurrentDirectory(new File("d:/d_other"));
// 파일 선택만 도와주고 파일을 실제로 열거나 저장하진 않음
// 열기용 창
// int result = chooser.showOpenDialog(new Panel());
// 저장용 창
int result = chooser.showSaveDialog(new Panel());
// '저장' 또는 '열기' 버튼을 눌렀을 경우
if (result == JFileChooser.APPROVE_OPTION) {
// 선택한 파일 객체 구하기
selectedFile = chooser.getSelectedFile();
// System.out.println("선택한 파일 : " + selectedFile.getAbsolutePath());
// 선택한 파일 정보를 이용해서 실제 읽기 또는 쓰기 작업을 수행
}
return selectedFile;
}
}
🍂 실행 결과
'JAVA' 카테고리의 다른 글
[JAVA] 입출력(I/O) Stream - 3 (보조스트림) (0) | 2021.08.06 |
---|---|
[JAVA] 입출력(I/O) - 1 (0) | 2021.08.04 |
[JAVA] 스레드의 동기화 - 2 (0) | 2021.08.04 |
[JAVA] 스레드의 동기화 - 1 (0) | 2021.08.03 |
[JAVA] 멀티 스레드 - 2 (0) | 2021.07.30 |