파일 을 쓰 는 6 가지 방법 중 성능 이 가장 좋다.

14611 단어 자바
자바 에서 파일 을 조작 하 는 방법 은 본질 적 으로 두 가지 밖 에 없다. 문자 흐름 과 바이트 흐름, 그리고 바이트 흐름 과 문자 흐름 의 실현 류 가 매우 많 기 때문에 파일 을 기록 할 때 우 리 는 다양한 종 류 를 선택 하여 실현 할 수 있다.우리 본 고 는 이 방법 들 을 점검 하 는 동시에 그들의 성능 을 테스트 하여 우리 에 게 가장 좋 은 기록 방법 을 선택 할 수 있 도록 한다.
본 격 적 으로 시작 하기 전에 우 리 는 먼저 몇 가지 기본 적 인 개념 인 흐름, 바이트 흐름 과 문자 흐름 의 정의 와 차 이 를 알 아 보 자.
0. 무엇이 흐름 입 니까?
자바 의 '흐름' 은 추상 적 인 개념 이자 비유 이다. 마치 물 흐름 처럼 물 흐름 은 한 끝 에서 다른 한 끝 으로 흐 르 고 자바 에서 의 '흐름' 은 바로 데이터 이 며 데 이 터 는 한 끝 에서 '흐름' 다른 한 끝 으로 흐른다.
흐름 의 방향 성에 따라 우 리 는 흐름 을 입력 흐름 과 출력 흐름 으로 나 눌 수 있 습 니 다. 프로그램 이 데이터 원본 에서 데 이 터 를 읽 어야 할 때 입력 흐름 이 열 립 니 다. 반대로 데 이 터 를 특정한 데이터 원본 목적지 에 쓸 때 도 출력 흐름 이 열 립 니 다. 데이터 원본 은 파일, 메모리 또는 네트워크 등 이 될 수 있 습 니 다.
1. 바이트 흐름 이란 무엇 인가?
바이트 흐름 의 기본 단 위 는 바이트 (Byte) 이 고 한 바이트 는 보통 8 자리 이 며 바 이 너 리 (데이터) 를 처리 하 는 데 사용 된다.바이트 흐름 은 두 가지 기본 클래스 가 있 습 니 다. InputStream (입력 바이트 흐름) 과 OutputStream (출력 바이트 흐름).
상용 바이트 흐름 의 계승 관계 도 는 다음 그림 과 같다. 그 중에서 InputStream 는 읽 기 동작 에 사용 되 고 OutputStream 는 쓰기 동작 에 사용 된다.
2. 문자 흐름 이란 무엇 인가?
문자 흐름 의 기본 단 위 는 유 니 코드 이 고 크기 는 두 바이트 (Byte) 이 며 텍스트 데 이 터 를 처리 하 는 데 사 용 됩 니 다.문자 흐름 의 두 기본 클래스: Reader (입력 문자 흐름) 과 Writer (출력 문자 흐름).
상용 문자 흐름 의 계승 관계 도 는 다음 그림 과 같다.
3. 흐름 의 분류
흐름 은 서로 다른 차원 에 따라 분류 할 수 있다. 예 를 들 어 흐름 의 방향 에 따라 분류 할 수도 있 고 전송 하 는 단위 에 따라 분류 할 수도 있 으 며 흐름 의 기능 에 따라 분류 할 수도 있다. 예 를 들 어 다음 과 같은 몇 가지 이다.
① 흐름 에 따라 분류
  • 출력 흐름: OutputStreamWriter 기류 로 삼다.
  • 입력 흐름: InputStreamReader 을 기본 클래스 로 합 니 다.

  • ② 전송 데이터 단위 별 분류
  • 바이트 흐름: OutputStreamInputStream 을 기본 으로 한다.
  • 문자 흐름: Writer 와 Reader 기류 로 삼다.

  • ③ 기능 별 분류
  • 바이트 흐름: 특정한 곳 (노드) 에서 데 이 터 를 읽 거나 쓸 수 있 습 니 다.
  • 처리 흐름: 이미 존재 하 는 흐름 에 대한 연결 과 패 키 징 으로 포 장 된 흐름 의 기능 호출 을 통 해 데이터 읽 기와 쓰 기 를 실현 합 니 다.

  • PS: 우 리 는 보통 데 이 터 를 전송 하 는 단위 로 분류 합 니 다.
    4. 파일 을 쓰 는 6 가지 방법
    파일 을 쓰 는 방법 은 주로 문자 흐름 Writer 에서 비롯 됩 니 다. 출력 바이트 흐름 OutputStream 의 하위 클래스 는 다음 그림 과 같다.
    이상 표시✅번호 의 클래스 는 파일 기록 을 실현 하 는 클래스 입 니 다. 그 밖 에 JDK 1.7 에서 도 제 공 됩 니 다 Files. 클래스 는 파일 에 대한 각종 조작 을 실현 하 는 데 쓰 인 다. 다음은 우리 가 각각 살 펴 보 자.
    방법 1: FileWriterFileWriter  '문자 흐름' 시스템 의 일원 이자 파일 기록 의 기본 클래스 입 니 다. 5 개의 구조 함 수 를 포함 하여 구체 적 인 파일 위 치 를 전달 하거나 File 대상, 두 번 째 매개 변 수 는 파일 을 추가 할 지 여 부 를 표시 합 니 다. 기본 값 은 false 파일 내용 을 추가 하 는 것 이 아니 라 파일 내용 을 다시 쓰 는 것 을 표시 합 니 다. (파일 을 추가 하 는 방법 에 대해 서 는 나중에 말씀 드 리 겠 습 니 다.)FileWriter 류 의 실현 은 다음 과 같다.
    /**
      *    1:   FileWriter    
      * @param filepath     
      * @param content       
      * @throws IOException
      */
    public static void fileWriterMethod(String filepath, String content) throws IOException {
        try (FileWriter fileWriter = new FileWriter(filepath)) {
            fileWriter.append(content);
        }
    }

    구체 적 인 파일 경로 와 기록 할 내용 만 입력 하면 됩 니 다. 호출 코드 는 다음 과 같 습 니 다.
    public static void main(String[] args) {
        fileWriterMethod("/Users/mac/Downloads/io_test/write1.txt", "  ,Java    .");
    }

    그리고 우 리 는 기 록 된 파일 을 열 었 습 니 다. 결 과 는 다음 과 같 습 니 다.
    자원 방출 에 관 한 문제: JDK 7 이상 버 전에 서 는 try - with - resource 방식 만 사용 하면 자원 의 방출 을 실현 할 수 있 습 니 다. 예 를 들 어 try (FileWriter fileWriter = new FileWriter (filepath) {...} 을 사용 하면 FileWriter 자원 의 자동 방출 을 실현 할 수 있 습 니 다.
    방법 2: Buffered WriterBufferedWriter  문자 흐름 시스템 의 일원 에 속 합 니 다. FileWriter 다른 것 은 BufferedWriter 자체 버퍼 입 니 다. 따라서 파일 을 쓰 는 성능 이 더 높 습 니 다. (다음 글 은 두 사람 을 테스트 합 니 다)
    작은 지식 포인트: 버퍼
    버퍼 는 캐 시 라 고도 부 르 며 메모리 공간의 일부분 입 니 다.즉, 메모리 공간 에 일정한 저장 공간 을 남 겨 두 었 는데 이런 저장 공간 은 입력 이나 출력 데 이 터 를 버퍼 링 하 는데 이 부분 에 남 겨 진 공간 을 버퍼 라 고 한다.
    버퍼 의 장점 은 파일 흐름 의 기록 을 예 로 들 면 버퍼 를 사용 하지 않 으 면 CPU 를 쓸 때마다 저속 저장 장치, 즉 디스크 와 상호작용 을 한다. 그러면 전체 파일 을 쓰 는 속 도 는 저속 저장 장치 (디스크) 에 제약 을 받는다.그러나 버퍼 를 사용 하면 쓰기 동작 을 할 때마다 데 이 터 를 고속 버퍼 메모리 에 저장 하고 버퍼 의 데이터 가 특정한 한도 값 에 도달 한 후에 파일 을 디스크 에 한꺼번에 기록 합 니 다.메모리 의 기록 속도 가 디스크 의 기록 속도 보다 훨씬 크기 때문에 버퍼 가 있 으 면 파일 의 기록 속도 가 크게 향상 된다.
    캐 시 구역 의 장점 을 알 게 된 후에 우 리 는 본 고의 주제 로 돌아 갔다. 그 다음 에 우 리 는 BufferedWriter 로 파일 을 기록 하고 코드 는 다음 과 같다.
    /**
     *    2:   BufferedWriter    
     * @param filepath     
     * @param content       
     * @throws IOException
     */
    public static void bufferedWriterMethod(String filepath, String content) throws IOException {
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filepath))) {
            bufferedWriter.write(content);
        }
    }

    호출 코드 는 방법 1 과 유사 하 므 로 여 기 는 더 이상 군말 하지 않 겠 습 니 다.
    방법 3: PrintWriterPrintWriter  또한 문자 흐름 시스템 의 일원 에 속 합 니 다. '문자 인쇄 흐름' 이 라 고 하지만 이 를 사용 하면 파일 의 기록 을 실현 할 수 있 습 니 다. 코드 는 다음 과 같 습 니 다.
    /**
     *    3:   PrintWriter    
     * @param filepath     
     * @param content       
     * @throws IOException
     */
    public static void printWriterMethod(String filepath, String content) throws IOException {
        try (PrintWriter printWriter = new PrintWriter(new FileWriter(filepath))) {
            printWriter.print(content);
        }
    }

    상기 코드 를 통 해 알 수 있 듯 이 PrintWriter 이 든 BufferedWriter 이 든 모두 FileWriter 를 바탕 으로 해 야 한다. 클래스 로 호출 완료.
    방법 4: FileOutputStream
    위의 세 가지 예 는 문자 흐름 이 파일 에 쓰 이 는 것 에 대한 작업 이 며, 그 다음 에 우 리 는 바이트 흐름 을 사용 하여 파일 기록 을 완성 할 것 입 니 다.우 리 는 사용 할 것 이다 String 자체 적 인 getBytes() 방법 은 문자열 을 바 이 너 리 파일 로 변환 한 다음 에 파일 을 기록 합 니 다. 이 구현 코드 는 다음 과 같 습 니 다.
    /**
     *    4:   FileOutputStream    
     * @param filepath     
     * @param content       
     * @throws IOException
     */
    public static void fileOutputStreamMethod(String filepath, String content) throws IOException {
        try (FileOutputStream fileOutputStream = new FileOutputStream(filepath)) {
            byte[] bytes = content.getBytes();
            fileOutputStream.write(bytes);
        }
    }

    방법 5: BufferedOutputStreamBufferedOutputStream  바이트 흐름 시스템 의 일원 에 속 합 니 다. FileOutputStream 다른 것 은 버퍼 기능 을 가지 고 있 기 때문에 성능 이 더 좋 습 니 다. 실현 코드 는 다음 과 같 습 니 다.
    /**
     *    5:   BufferedOutputStream    
     * @param filepath     
     * @param content       
     * @throws IOException
     */
    public static void bufferedOutputStreamMethod(String filepath, String content) throws IOException {
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(filepath))) {
            bufferedOutputStream.write(content.getBytes());
        }
    }

    방법 6: Files
    다음 작업 방법 은 이전 코드 와 다 릅 니 다. 다음은 JDK 7 에서 제공 하 는 새로운 파일 작업 클래스 Files 를 사용 하 겠 습 니 다. 파일 의 기록 을 실현 합 니 다.Files  클래스 는 JDK 7 에 추 가 된 새로운 작업 파일 의 클래스 입 니 다. 파일 복사, 읽 기, 쓰기, 파일 속성 가 져 오기, 파일 디 렉 터 리 바로 옮 기기 등 파일 을 처리 하 는 방법 을 많이 제공 합 니 다. 이 방법 들 은 파일 의 작업 을 편리 하 게 해 줍 니 다. 구현 코드 는 다음 과 같 습 니 다.
    /**
     *    6:   Files    
     * @param filepath     
     * @param content       
     * @throws IOException
     */
    public static void filesTest(String filepath, String content) throws IOException {
        Files.write(Paths.get(filepath), content.getBytes());
    }

    이상 의 이 방법 들 은 모두 파일 의 기록 을 실현 할 수 있 습 니 다. 어떤 방법 이 성능 이 더 좋 습 니까?이제 테스트 해 보 겠 습 니 다.
    5. 성능 테스트
    우 리 는 먼저 비교적 큰 문자열 을 구축 한 다음 에 상기 6 가지 방법 으로 파일 의 기록 속 도 를 테스트 한 다음 에 결 과 를 인쇄 합 니 다. 테스트 코드 는 다음 과 같 습 니 다.
    import java.io.*;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    public class WriteExample {
        public static void main(String[] args) throws IOException {
            //       
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < 1000000; i++) {
                stringBuilder.append("ABCDEFGHIGKLMNOPQRSEUVWXYZ");
            }
            //     
            final String content = stringBuilder.toString();
            //        
            final String filepath1 = "/Users/mac/Downloads/io_test/write1.txt";
            final String filepath2 = "/Users/mac/Downloads/io_test/write2.txt";
            final String filepath3 = "/Users/mac/Downloads/io_test/write3.txt";
            final String filepath4 = "/Users/mac/Downloads/io_test/write4.txt";
            final String filepath5 = "/Users/mac/Downloads/io_test/write5.txt";
            final String filepath6 = "/Users/mac/Downloads/io_test/write6.txt";
    
            //    :   FileWriter    
            long stime1 = System.currentTimeMillis();
            fileWriterTest(filepath1, content);
            long etime1 = System.currentTimeMillis();
            System.out.println("FileWriter     :" + (etime1 - stime1));
    
            //    :   BufferedWriter    
            long stime2 = System.currentTimeMillis();
            bufferedWriterTest(filepath2, content);
            long etime2 = System.currentTimeMillis();
            System.out.println("BufferedWriter     :" + (etime2 - stime2));
    
            //    :   PrintWriter    
            long stime3 = System.currentTimeMillis();
            printWriterTest(filepath3, content);
            long etime3 = System.currentTimeMillis();
            System.out.println("PrintWriterTest     :" + (etime3 - stime3));
    
            //    :   FileOutputStream     
            long stime4 = System.currentTimeMillis();
            fileOutputStreamTest(filepath4, content);
            long etime4 = System.currentTimeMillis();
            System.out.println("FileOutputStream     :" + (etime4 - stime4));
    
            //    :   BufferedOutputStream    
            long stime5 = System.currentTimeMillis();
            bufferedOutputStreamTest(filepath5, content);
            long etime5 = System.currentTimeMillis();
            System.out.println("BufferedOutputStream     :" + (etime5 - stime5));
    
            //    :   Files    
            long stime6 = System.currentTimeMillis();
            filesTest(filepath6, content);
            long etime6 = System.currentTimeMillis();
            System.out.println("Files     :" + (etime6 - stime6));
    
        }
    
        /**
         *    :   Files    
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void filesTest(String filepath, String content) throws IOException {
            Files.write(Paths.get(filepath), content.getBytes());
        }
    
        /**
         *    :   BufferedOutputStream    
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void bufferedOutputStreamTest(String filepath, String content) throws IOException {
            try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                    new FileOutputStream(filepath))) {
                bufferedOutputStream.write(content.getBytes());
            }
        }
    
        /**
         *    :   FileOutputStream     
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void fileOutputStreamTest(String filepath, String content) throws IOException {
            try (FileOutputStream fileOutputStream = new FileOutputStream(filepath)) {
                byte[] bytes = content.getBytes();
                fileOutputStream.write(bytes);
            }
        }
    
        /**
         *    :   PrintWriter    
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void printWriterTest(String filepath, String content) throws IOException {
            try (PrintWriter printWriter = new PrintWriter(new FileWriter(filepath))) {
                printWriter.print(content);
            }
        }
    
        /**
         *    :   BufferedWriter    
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void bufferedWriterTest(String filepath, String content) throws IOException {
            try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filepath))) {
                bufferedWriter.write(content);
            }
        }
    
        /**
         *    :   FileWriter    
         * @param filepath     
         * @param content       
         * @throws IOException
         */
        private static void fileWriterTest(String filepath, String content) throws IOException {
            try (FileWriter fileWriter = new FileWriter(filepath)) {
                fileWriter.append(content);
            }
        }
    }

    결 과 를 보기 전에 저 희 는 먼저 대응 하 는 폴 더 에 가서 기 록 된 파일 이 정상 적 인지 확인 하 겠 습 니 다. 다음 그림 에서 보 듯 이 문자 흐름 의 조작 속도 가 가장 빠 릅 니 다. 이것 은 저희 가 이번에 테스트 한 코드 가 문자열 이기 때문에 바이트 흐름 을 사용 할 때 문자열 을 바이트 흐름 으로 바 꿔 야 하기 때문에 실행 효율 에 있어 서 우세 하지 않 습 니 다.
    이 같은 결 과 를 통 해 알 수 있 듯 이 성능 이 가장 좋 은 것 은 버퍼 가 있 는 문자열 쓰기 흐름 BufferedWriter 이 고 성능 이 가장 느 린 것 은 Files 이다.
    PS: 이상 의 테스트 결 과 는 문자열 의 조작 장면 에 만 유효 합 니 다. 바 이 너 리 파일 을 조작 했다 면 버퍼 가 있 는 바이트 흐름 Buffered OutputStream 을 사용 해 야 합 니 다.
    6. 확장 지식: 내용 추가
    상기 코드 는 파일 을 다시 쓸 것 입 니 다. 기 존 에 내용 을 추가 하려 면 기록 흐름 을 만 들 때 하 나 를 더 설정 해 야 합 니 다 append. 의 매개 변 수 는 true 입 니 다. 예 를 들 어 우리 가 사용 하면 FileWriter 파일 의 추가 가 이 루어 지면 구현 코드 는 다음 과 같 습 니 다.
    public static void fileWriterMethod(String filepath, String content) throws IOException {
        //     append         true =        
        try (FileWriter fileWriter = new FileWriter(filepath, true)) {
            fileWriter.append(content);
        }
    }

    하면, 만약, 만약... 또는 BufferedWriter 도 구축 해 야 한다 PrintWriter 유사 시 하나 더 설정 new FileWriter 의 매개 변 수 는 append 이 고 실현 코드 는 다음 과 같다.
    try (BufferedWriter bufferedWriter = new BufferedWriter(
        new FileWriter(filepath, true))) {
        bufferedWriter.write(content);
    }
    true 클래스 가 파일 의 추가 쓰기 방법 을 실현 하려 면 Files 방법 을 호출 할 때 write 인 자 를 하나 더 전달 해 야 합 니 다. 실현 코드 는 다음 과 같 습 니 다.
    Files.write(Paths.get(filepath), content.getBytes(), StandardOpenOption.APPEND);

    7. 총화
    본 고 는 6 가지 파일 을 쓰 는 방법 을 보 여 주 었 는데 이 6 가지 방법 은 모두 3 가지 로 나 뉜 다. 문자 흐름 쓰기, 바이트 흐름 쓰기 와 StandardOpenOption.APPEND 클래스 기록.그 중에서 조작 이 가장 편리 한 것 은 Files 류 이지 만 성능 이 그다지 좋 지 않다.성능 에 대한 요구 가 있 으 면 캐 시 영역 이 있 는 흐름 을 사용 하여 작업 을 수행 하 는 것 을 추천 합 니 다. 예 를 들 어 Files 또는 BufferedWriter.기 록 된 내용 이 문자열 이 라면 사용 BufferedOutputStream 을 추천 하고, 기 록 된 내용 이 바 이 너 리 파일 이 라면 사용 BufferedWriter 을 추천 합 니 다.
    참고 & 감사
    https://www.cnblogs.com/absfree/p/5415092.html
    공중 번호 '자바 중국어 공동체' 에 주목 하여 더 많은 건어물 을 발견 하 다.

    좋은 웹페이지 즐겨찾기