본문 바로가기
JAVA

[JAVA] 입출력(I/O) Stream - 2

by happenstance 2021. 8. 5.

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) {
		}
	}
}

실행 결과
생성된 testChar.txt

 

 

🌳 한글이 저장된 파일 읽어오기 (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