[코드스테이츠 백엔드 44기 SEB BE] 18일차

오태호·2023년 3월 9일
0

코드스테이츠

목록 보기
16/22
post-thumbnail

InputStream, OutputStream

  • 입출력을 다루기 위한 클래스
  • 스트림은 단방향으로만 데이터를 전송할 수 있다
    • 입력과 출력을 동시에 처리하기 위해서는 각각의 스트림이 필요하다!
  • 입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉘어진다
    • Ex. File을 다룰 때는 FileInputStream / FileOutputStream을 사용한다
    • Ex. process를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다

FileInputStream

public class FileInputStreamExample {
    public static void main(String[] args) {
        try {
            FileInputStream fileInputStream = new FileInputStream("파일 경로");
            int idx = 0;
            while((idx = fileInputStream.read()) != -1) {
                System.out.print((char)idx);
            }
            fileInputStream.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
  • FileInputStream은 위와 같이 사용할 수 있다
  • BufferedInputStream이라는 보조 스트림을 사용하면 성능이 향상되므로, 대부분의 경우 이를 사용한다
    • 버퍼(Buffer)
      • 바이트 배열
      • 여러 바이트들을 저장하여 한 번에 많은 양의 데이터를 입출력할 수 있도록 도와주는 임시 저장 공간
public BufferedInputStreamExample {
    public static void main(String[] args) {
        try {
            FileInputStream fileInputStream = new FileInputStream("파일 경로");
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

            int idx = 0;
            while((idx = bufferedInputStream.read()) != -1) {
                System.out.print((char)idx);
            }
            fileInputStream.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
  • BufferedInputStream 보조 스트림도 FileInputStream과 같이 스트림의 하위 클래스이기 때문에 입출력 방법은 같다

FileOutputStream

public class FileOutputStreamExample {
    public static void main(String[] args) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("파일 경로");
            String word = "Hello Java!";

            byte[] bytes = word.getBytes();
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
  • 위 코드를 통해 "Hello Java!"라는 문자열이 입력된 파일이 해당 경로에 생성된다
    • 만약 해당 파일이 이미 존재한다면, 내용이 "Hello Java!"로 덮어씌워진다

FileReader / FileWriter

  • File 입출력 스트림(FileInputStream / FileOutputStream)은 바이트 기반 스트림
    • 즉, 입출력 단위가 1byte
  • 그런데 자바에서 char 타입은 2 byte
    • File 입출력 스트림에서 입출력하는 단위와 다르다
  • 이를 해소하기 위해 문자 기반 스트림을 제공한다
    • FileReader / FileWriter
    • 문자 기반 스트림 -> 문자를 다룰 때 사용한다
    • 문자 기반 스트림과 그 하위 클래스는 여러 종류의 인코딩과 자바에서 사용하는 유니코드 간의 변환을 자동으로 처리해준다
  • 문자 기반 스트림에는 일반적으로 바이트 기반 스트림의 InputStream이 Reader로, OutputStream이 Writer로 대응된다
    • FileInputStream이 문자 기반에서는 FileReader, FileOutputStream은 FileWriter에 해당하는 것과 같다
    • 문자 기반 스트림 및 그 하위 클래스는 여러 종류의 인코딩과 자바에서 사용하는 유니코드 간의 변환을 자동으로 처리해주므로, FileReader는 인코딩을 유니코드로, FileWriter는 유니코드를 인코딩으로 변환해준다

FileReader

public class FileReaderExample {
    public static void main(String[] args) {
        String file = "파일 경로";
        try {
            FileReader fileReader = new FileReader(file);

            int character = 0;

            // 문자를 읽어와 그 값이 -1이 아닐 때까지 문자를 읽어옴
            while((character = fileReader.read()) != -1) {
                System.out.println((char)character);
            }

            fileReader.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}
  • 파일에 한글이 존재하더라도 자동으로 해당 인코딩을 유니코드로 변경해주기 때문에 잘 출력된다
  • 성능을 개선할 수 있는 BufferedReader가 존재한다
public class BufferedReaderExample {
    public static void main(String[] args) {
        String file = "파일 경로";
        try {
            FileReader fileReader = new FileReader(file);BufferedReader bufferedReader = new BufferedReader(fileReader);

            int character = 0;

            // 문자를 읽어와 그 값이 -1이 아닐 때까지 문자를 읽어옴
            while((character = bufferedReader.read()) != -1) {
                System.out.println((char)character);
            }

            fileReader.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

FileWriter

public class FileWriterExample {
    public static void main(String[] args) {
        String file = "파일 경로";
        try {
            FileWriterExample fileWriter = new FileWriterExample(file);

            String str = "Hello Java!";

            // str 내용이 써진 파일이 생성됨
            // 파일이 이미 존재한다면 str 내용으로 덮어씌워짐
            fileWriter.write(str);
            fileWriter.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

close() vs flush()

  • close() : 스트림을 우선 플러쉬한 후에 스트림을 닫는다
  • flush() : 스트림을 플러쉬한다
  • 어차피 close()를 하면 플러쉬가 되는데 flush()를 왜 사용하는가?
    • close()는 스트림을 닫는데, flush()는 스트림을 닫지 않는다
    • 즉, 스트림을 닫지 않은 상태로 바이트를 보내고 싶은 경우에 flush()를 사용한다!
      • Ex. 버퍼의 크기가 10000인데 버퍼 안에 10000만큼의 바이트가 존재한다
      • 그런데 이후에 더 바이트가 들어온다면, 스트림을 닫아서는 안된다
      • 이러한 경우에 flush()를 통해 버퍼링되어있는 바이트들을 쓰고 이후에 들어오는 바이트들을 버퍼에 넣는다

File

  • File 클래스
    • 파일과 디렉토리에 접근할 수 있도록 도와준다
public class FileExample {
    public static void main(String[] args) {
        File file = new File("파일 경로");

        System.out.println(file.getPath());
        System.out.println(file.getParent());
        System.out.println(file.getCanonicalPath());
        System.out.println(file.canWrite());
    }
}
  • File의 path를 가져오는 API들
    • getPath()
      • File에 입력한 경로를 그대로 반환한다
      • 만약 인자로 전달한 경로가 상대 경로라면 getPath()도 상대 경로를 반환한다
    • getAbsolutePath()
      • 현재 실행 중인 Working directory에 File에 전달한 경로를 조합하여 절대 경로를 반환한다
    • getCanonicalPath()
      • 절대 경로를 반환한다
      • ./, ../와 같은 경로들을 정리하고 반환해준다
      • Symbolic link 파일이라면 그것과 연결된 파일의 경로를 반환한다
File file = new File("../example/path/../path/file");

System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());

// 결과값
/home/IdeaProjects/example/../example/path/../path/file
/home/IdeaProjects/example/path/file
  • File 인스턴스를 생성하는 것이 파일을 생성하는 것은 아니다
    • 파일 생성을 위해서는 File 인스턴스를 생성할 때 첫 번째 인자에 경로를, 두 번째 인자에 파일명을 작성하고, createNewFile() 메서드를 호출해준다
File file = new File("../", "fileInstance.txt");
file.createNewFile();
  • 파일명을 변경하고 싶을 때는 renameTo() 메서드를 사용한다
public class FileExample {
    public static void main(String[] args) {
        File parent = new File("./");
        File[] fileList = parent.listFiles(); // parent 위치에 있는 파일들을 모두 가져옴

        String prefix = "renameFile";

        for(int idx = 0; idx < fileList.length; idx++) {
            String fileName = fileList[idx].getName();
            if(fileName.endWith("txt")) // 해당 파일이 txt 확장자를 갖고 있다면
                list[idx].renameTo(new File(parent, prefix + fileName)); // prefix를 붙인 것으로 파일 이름 변경
        }
    }
}
profile
자바, 웹 개발을 열심히 공부하고 있습니다!

0개의 댓글