Java/Java Effective

5. 파일입출력(I/O)

mozzi329 2022. 7. 20. 00:00
728x90
 

 

     

    호로로로록

    📌 InputStream / OutputStream

    자바에서 제공하는 입출력 스트림으로, 입력과 출력을 동시에 처리하기 위한 스트림이다.

    입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉜다. 예를 들면, File을 다룰 때에는 FileInputStream / FileOutputStream을 사용하고, 프로세스를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다.

    ※ Stream이란?

    개별 바이트나 문자열인 데이터의 원천

    파일을 읽거나 쓸 때, 네트워크 소켓을 거쳐 통신할 때 쓰이는 추상적인 개념

     

    ✔️ InputStream 메서드 종류

    메서드명 리턴 타입 기능
    available() int 현재 읽을 수 있는 바이트의 수를 반환한다.
    close() void 입력 스트림을 닫는다.
    mark(int readlimit) void 입력 스트림에서 현재의 위치를 표시해준다.
    markSupported() boolean 해당 입력 스트림에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다.
    read() abstract int 입력스트림에서 1Byte를 읽어 int 값으로 반환(실제로 읽어들인 값을 반환)하며 더이상 읽어드릴 값이 없을 경우 -1을 반환한다.
    read(byte[] b) int 입력 스트림에서 buf[] 크기만큼 읽어 buf에 저장하고, 읽은 바이트 수를 반환한다.
    read(byte[] b, int off, int len) int b[off]에서 len개까지의 데이터를 읽고 읽은 바이트 수를 반환한다.
    reset() void mark()를 마지막으로 호출한 위치로 이동한다.
    skip(long n) long 입력 스트림에서 지정된 바이트만큼 무시하고, 무시된 바이트 수를 반환한다.

     

    ✔️ OutputStream 메서드 종류

    메서드명 리턴 타입 기능
    close() void 출력 스트림을 닫는다.
    flush() void 버퍼에 남아있는 데이터를 모두 출력시키고 버퍼를 비우는 역할을 한다.
    write(byte[] b) void 바이트 배열을 출력 스트림에 넣는다.
    write(byte[] b, int off, int len) void b[off]에서 len개까지의 바이트 배열의 바이트를 출력 스트림에 넣는다.
    write(int b) abstract void 매개변수로 주어진 int 값에서 끝에 있는 1Byte만을 출력 스트림으로 보낸다.

     

    ✔️ FileInputStream

    자바에서 많이 사용되는 FileInputStream은 대표적인 바이트 기반 스트림으로, 다음과 같이 스트림을 생성할 수 있다.

    FileInputStream 변수명 = new FileInputStream(파일경로);
    

     

    파일을 읽어오는 기본 구조는 아래 예제 코드와 같다.

    import java.io.FileInputStream;
    
    public class FileInputStreamExample {
        public static void main(String args[])
        {
            try {
    	// 입력 : 파일 경로
                FileInputStream fileInput = new FileInputStream("hi.txt");
                int i = 0;
    
    	//fileInput.read()의 리턴값을 i에 저장한 후, 값이 -1인지 확인한다.
                while ((i = fileInput.read()) != -1) { 
                    System.out.print((char)i);
                }
                fileInput.close();
            }
            catch (Exception e) {
                System.out.println(e);
            }
        }
    }

     

    ❗️BufferedInputStream

    성능 향상을 위한 보조 스트림

    성능이 향상되기 때문에 파일을 불러올 때 같이 많이 사용된다. 여기서 BufferedInputStream은 바이트 배열로서, 여러 바이트를 저장하여 한번에 많은 양의 데이터를 입출력 할 수 있도록 도와주는 임시 저장 공간 역할을 한다.

    import java.io.FileInputStream;
    import java.io.BufferedInputStream;
    
    public class FileInputStreamExample {
        public static void main(String args[])
        {
            try {
                FileInputStream fileInput = new FileInputStream("hi.txt");
    	BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
                int i = 0;
                while ((i = bufferedInput.read()) != -1) {
                    System.out.print((char)i);
                }
                fileInput.close();
            }
            catch (Exception e) {
                System.out.println(e);
            }
        }
    }

     

    ✔️ FileOutputStream

    자바에서 많이 사용되는 FileOutputStream은 대표적인 바이트 기반 스트림으로, 다음과 같이 스트림을 생성할 수 있다.

    FileOutputStream fileOutput = new FileOutputStream(파일 경로);
    

     

    import java.io.FileOutputStream;
    
    public class FileOutputStreamExample {
        public static void main(String args[]) {
            try {
                FileOutputStream fileOutput = new FileOutputStream("hi.txt");
                String word = "code";
    
                byte b[] = word.getBytes();
                fileOutput.write(b);
                fileOutput.close();
            }
            catch (Exception e) {
                System.out.println(e);
            }
        }
    }
    

    위 코드를 실행하면, 같은 디렉토리 내에 code라는 문자열이 입력된 hi.txt 파일이 생성됨을 확인할 수 있다.

     

    📌 FileReader / FileWriter

    자바에서 제공하는 대표적인 문자 기반 스트림

    앞서 살펴본 File 입출력 스트림은, 바이트 기반 스트림이다. 바이트 기반은 입출력 단위가 1byte라는 뜻이다. 하지만 Java에서 char 타입은 2byte(자바 기본 유닛 참고)이다. 이 두 차이를 해소하기 위해 자바에서는 문자 기반 스트림을 제공한다. 문자 기반 스트림에는 FileReader와 FileWriter가 있다.

     

    FileReader는 인코딩을 유니코드로 변환하고, FileWriter는 유니코드를 인코딩으로 변환한다.

     

    ✔️ FileReader

    public class FileReaderExample {
        public static void main(String args[]) {
            try {
                String fileName = "hi.txt";
                FileReader file = new FileReader(fileName);
    
                int data = 0;
    
                while((data=file.read()) != -1) {
                    System.out.print((char)data);
                }
                file.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    hi.txt에 한글을 입력하고 저장한 뒤 FileReader를 통해 값을 읽어올 수 있다. 또한 InputStream과 동일한 메서드를 사용할 수 있다.

     

    ❗️BufferedReader

    성능 향상을 위한 보조 리더 버퍼

    바이트 기반 스트림과 마찬가지로 Reader에도 성능을 개선할 수 있는 BufferedReader가 있다.

    FileReader file = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(file);

     

    ✔️ FileWriter

    public class FileWriterExample {
        public static void main(String args[]) {
            try {
                String fileName = "hi.txt";
                FileWriter writer = new FileWriter(fileName);
    
                String str = "written!";
                writer.write(str);
                writer.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    앞서 만든 hi.txt 파일에 “written!”이라는 문자열을 입력하는 예제이다. OutputStream과 동일한 메서드를 사용할 수 있다.

     

    📌 File

    자바에서 파일과 디렉토리에 접근하고 제어하기 위해 사용하는 클래스

    ✔️ File의 생성자

    생성자 설명
    File(String pathname) 입력한 pathname(파일명 포함) 경로 파일의 객체를 생성한다.
    File(String parent, String child) parent 디렉토리 경로의 child 파일에 대한 객체를 생성한다.
    File(File parent, String child) 파일 객체 parent의 child 파일에 대한 객체를 생성한다.
    File(URI uri) uri 경로에 대한 파일 객체를 생성한다.

     

    ✔️ File의 메서드

    메소드 설명
    File getAbsoluteFile() 파일의 절대 경로를 반환한다.
    String getAbsolutePath() 파일의 절대 경로를 문자열로 반환한다.
    File getCanonicalFile() 파일의 정규 경로를 반환한다.
    String getCanonicalPath() 파일의 정규 경로를 문자열로 반환한다.
    String getName() 파일이나 폴더의 이름을 넘겨준다.
    String getParent() 부모 경로에 대한 경로명을 문자열로 반환한다.
    File getParentFile() 부모 폴더를 File의 형태로 반환한다.
    String getPath() 파일의 경로를 문자열의 형태로 반환한다.
    long getTotalSpace() 하드디스크의 총 용량을 반환한다.
    long getUsableSpace() 하드디스크의 사용 가능한 용량을 반환한다.
    long getFreeSpace() 하드디스크의 남은 공간을 반환한다.
    int hashCode() hash code를 반환한다.
    long lastModified() 해당 경로 파일의 최종 수정 일자를 반환한다.
    long length() 해당 경로 파일의 길이를 반환한다.
    Path toPath() java.nio.file.Path 객체로 반환한다.
    URI toURI() URI 형태로 파일 경로를 반환한다.
    File[] listRoots() 하드디스크의 루트 경로를 반환한다.
    String[] list() 경로의 파일들과 폴더를 문자열 배열로 반환한다.
    String[] list(FilenameFilter filter) filter에 만족되는 파일들과 폴더 이름을 문자열 배열로 반환한다.
    File[] listFiles() 해당 경로의 파일들과 폴더의 파일을 배열로 반환한다.
    File[] listFiles(FileFilter filter) filter에 만족되는 파일들과 폴더를 File 배열로 반환한다.
    File[] listFiles(FilenameFilter filter) filter에 만족되는 파일들과 폴더를 File 배열로 반환한다.

     

    ✔️ 파일 체크 관련 메서드

    메소드 설명
    boolean exists() 파일의 존재 여부를 반환한다.
    boolean isAbsolute() 해당 경로가 절대 경로인지 여부를 반환한다.
    boolean isDirectory() 해당 경로가 디렉토리인지 여부를 반환한다.
    boolean isFile() 해당 경로가 file 인지 여부를 반환한다.
    boolean isHidden() 해당 경로가 숨김 파일인지 여부를 반환한다.

     

    ✔️ 파일 권한 관련 메서드

    메소드 설명
    boolean canExecute() 파일 실행 권한이 있는지 여부를 반환한다.
    boolean canRead() 파일을 읽기 권한이 있는지 여부를 반환한다.
    boolean canWrite() 파일을 씨기 권한이 있는지 여부를 반환한다.
    boolean setExecutable(boolean executable) 파일 소유자의 실행 권한을 설정한다.
    boolean setExecutable(boolean executable, boolean ownerOnly) 파일의 실행 권한을 소유자 또는 모두에 대해 설정한다.
    boolean setReadable(boolean readable) 파일의 소유자의 읽기 권한을 설정한다.
    boolean setReadable(boolean readable, boolean ownerOnly) 파일의 읽기 권한을 소유자 또는 모두에 대해 설정한다.
    boolean setReadOnly() 파일을 읽기 전용으로 변경한다.
    boolean setWritable(boolean writable) 파일의 소유자의 쓰기 권한을 설정한다.
    boolean setWritable(boolean writable boolean ownerOnly) 파일의 쓰기 권한을 소유자 또는 모두에 대해 설정한다.

     

    ✔️ 예제

    import java.io.*;
    
    public class FileExample {
        public static void main(String args[]) throws IOException {
                File file = new File("../hi.txt");
    
                System.out.println(file.getPath());
                System.out.println(file.getParent());
                System.out.println(file.getCanonicalPath());
                System.out.println(file.canWrite());
        }
    }
    

     

    파일 인스턴스를 생성하는 것이 곧 파일을 생성하는 것은 아니다. 파일을 생성하기 위해서는 파일 인스턴스를 생성할 때 다음과 같이 첫 번째 인자에 경로를, 두 번째 인자에 파일명을 작성하고, createNewFile()메서드를 호출해주어야 한다.

    File file = new File("./", "newHi.txt");
    file.createNewFile();
    

     

    다음은 현재 디렉토리(.)에서 확장자가 .txt인 파일만을 대상으로, 파일명 앞에 “code”라는 문자열을 붙여주는 예제이다.

    import java.io.File;
    
    public class FileClassExample {
        public static void main(String[] args) {
    
            File parentDir = new File("./");
            File[] list = parentDir.listFiles();
            String prefix = "code";
    
            for(int i =0; i <list.length; i++) {
                String fileName = list[i].getName();
    
                if(fileName.endsWith("txt") && !fileName.startsWith("code")) {
                        list[i].renameTo(new File(parentDir, prefix + fileName));
                    }
            }
        }
    }