java 새 IO

24746 단어 자바
전통 적 IO
자바 의 InputStream,OutputStream,Reader,Writer 와 같은 흐름 을 위 한 입 출력 시스템 은 전통 적 인 IO 로 여 겨 진다.전통 적 인 IO 는 차단 식 입 출력 이 고 바이트 의 이동 을 통 해 처리 된다.즉,전통 적 인 IO 는 한 번 에 한 바이트 만 처리 할 수 있 고 효율 이 높 지 않다.
뉴 IO
새 IO 는 전통 적 인 IO 와 같은 목적 을 가지 고 있 으 며 모두 입 출력 기능 을 하 는 데 사용 된다.그러나 새 IO 는 메모리 맵 파일 방식 으로 입 출력 을 처리 합 니 다.새 IO 는 파일 이나 파일 의 한 부분 을 메모리 에 표시 합 니 다.그러면 메모리 에 접근 하 는 것 처럼 파일 에 접근 할 수 있 습 니 다.이런 방식 은 전통 적 인 IO 보다 훨씬 빠 릅 니 다.
자바 의 새로운 IO 관련 패 키 지 는 다음 과 같 습 니 다.
  • java.nio 패키지:주로 Buffer 와 관련 된 종 류 를 제공 합 니 다
  • java.nio.channel 패키지:주로 Channel 과 Selector 와 관련 된 클래스 를 포함한다
  • java.nio.charset 패키지:문자 집합 과 관련 된 클래스 를 포함 합 니 다
  • java.nio.channel.spi 패키지:채널 서 비 스 를 제공 하 는 클래스 를 포함 합 니 다
  • java.nio.charset.spi 패키지:문자 집합 서 비 스 를 제공 하 는 클래스 를 포함 합 니 다.여 기 는 주로 네 가지 채널,Buffer,Charset,Selector Channel 과 Buffer 와 관련 되 는데 채널 은 전통 적 인 입 출력 에 대한 시 뮬 레이 션 으로 새로운 IO 시스템 에서 모든 데 이 터 는 채널 을 통 해 전송 해 야 한다.Channel 과 전통 적 인 InputStream 과 OutputStream 의 가장 큰 차 이 는 map 방법 을 제공 하 는 것 입 니 다.이 map 방법 을 통 해'하나의 데이터'를 메모리 에 직접 표시 할 수 있 습 니 다.전통 적 인 IO 가 흐름 을 위 한 처리 라면 새 IO 는 블록 을 위 한 처리 입 니 다.Buffer 는 하나의 용기 로 이해 할 수 있 습 니 다.본질은 하나의 배열 입 니 다.Channel 로 보 내 는 모든 대상 은 Buffer 에 먼저 넣 어야 합 니 다.Channel 에서 읽 은 대상 도 Buffer 에 먼저 읽 어야 합 니 다.이름 그대로 버 퍼 는 버퍼 역할 을 한다.Charset 는 UNICODE 문자열 을 바이트 시퀀스 와 역 맵 으로 표시 하 는 데 사 용 됩 니 다.selector 클래스 는 비 차단 식 입 출력 작업 을 지원 합 니 다.Buffer 의 내부 구 조 는 하나의 배열 과 유사 하여 여러 가지 유형의 같은 데 이 터 를 저장 할 수 있 습 니 다.Buffer 는 추상 적 인 유형 으로 모든 기본 유형(boolean 제외)에 해당 하 는 Buffer 류 가 있다.예 를 들 어 ByteBuffer,Short Buffer,CharBuffer,IntBuffer,LongBuffer,Float Buffer,DoubleBuffer 등 이다.이러한 버 퍼 류 는 ByteBuffer 를 제외 하고 모두 같 거나 비슷 한 방법 으로 데 이 터 를 관리한다.이 Buffer 들 은 모두 구조 기 가 없 으 며,정적 인 XxBuffer allocate(int capacity)를 사용 하여 용량 이 capacity 인 Buffer 대상 을 만 듭 니 다.버 퍼 류 에 서 는 바 이 트 버 퍼 와 차 버 퍼 가 많이 사용 되 고,다른 버 퍼 류 에 서 는 덜 사용 된다.그 중에서 ByteBuffer 는 MappedByteBuffer 와 같은 하위 클래스 도 있 습 니 다.Channel 이 디스크 파일 의 부분 이나 모든 내용 을 메모리 에 비 추어 얻 은 결 과 를 나타 내 는 데 사 용 됩 니 다.보통 MappedByteBuffer 대상 은 Channel 의 map 방법 으로 되 돌아 갑 니 다.Buffer 에는 capacity(용량),limit(한계),position(위치)세 가지 중요 한 개념 이 있다

  • 4.567917.capacity:표지 Buffer 의 최대 용량 은 최대 몇 개의 데 이 터 를 저장 할 수 있 습 니까?capacity 는 마이너스 일 수 없습니다.생 성 후에 도 변경 할 수 없습니다.(이 점 은 배열 과 유사 하 다)
  • limit:첫 번 째 로 읽 거나 쓸 수 없 는 Buffer 위치 색인 입 니 다.즉,limit 뒤에 있 는 데 이 터 는 읽 을 수도 기록 할 수도 없다 는 것 이다
  • position:다음 읽 거나 쓸 수 있 는 버퍼 위치 색인(전통 IO 의 기록 지침 과 유사)을 가리 키 는 데 사 용 됩 니 다.Buffer 를 사용 하여 Channel 에서 데 이 터 를 읽 을 때 position 위치의 값 은 얼마나 많은 데 이 터 를 막 았 는 지 와 같 습 니 다.Buffer 대상 을 새로 만 들 때 position 는 0 입 니 다

  • 4.567917.그 밖 에 선택 할 수 있 는 태그 가 있 습 니 다.mark 는 position 를 mark 에 직접 찾 을 수 있 습 니 다.mark,position,limit,capacity 는 다음 과 같은 관 계 를 만족 시 킵 니 다:mark<=position<=limit<=capacity.Buffer 의 주요 역할 은 데 이 터 를 불 러 오고 데 이 터 를 출력 하 는 것 입 니 다.기록 한 후에 데 이 터 를 읽 을 때 position 와 limit 이 변화 합 니 다
  • Buffer 대상 이 처음 생 성 되 었 을 때 position 는 0 이 고 limit 은 capacity 입 니 다
  • 프로그램 호출 put 방법 은 Buffer 에 데 이 터 를 계속 채 우 고 데 이 터 를 채 울 때마다 Buffer 의 position 는 뒤로 이동 합 니 다
  • Buffer 충전 데이터 가 끝나 면 flip 방법 을 사용 하여 limit 을 position 가 있 는 위치 로 설정 한 다음 position 를 0 으로 설정 합 니 다

  • 4.567917.그러면 Buffer 에서 데 이 터 를 읽 을 수 있 고 데 이 터 를 읽 을 때마다 position 는 뒤로 이동 합 니 다
  • 데 이 터 를 읽 은 후에 clear 방법 을 사용 해 야 합 니 다.clear 방법 은 Buffer 의 데 이 터 를 비 우 는 것 이 아니 라 position 를 0 으로 리 셋 하고 limit 을 capacity 로 리 셋 하여 데이터 의 재 작성 을 기다 리 는 것 입 니 다.위의 절차 설명 에 따 르 면 Buffer 의 flip 방법 은 데 이 터 를 읽 기 위해 준 비 를 마 쳤 고 clear 방법 은 데 이 터 를 다시 쓰기 위해 준 비 를 마 쳤 음 을 알 수 있 습 니 다.put 와 get 은 Buffer 의 데 이 터 를 기록 하고 읽 는 방법 입 니 다.Buffer 는 단일 데이터 의 읽 기와 쓰기 도 지원 하고 일괄 읽 기와 쓰기 도 지원 합 니 다(배열 을 매개 변수 로).put 와 get 을 사용 하여 Buffer 의 데 이 터 를 읽 을 때 절대 와 상대 두 가지 로 나 뉜 다
  • 상대:Buffer 의 현재 위치 에서 데 이 터 를 읽 거나 기록 한 다음 에 position 의 값 을 처리 하 는 요소 개수 에 따라 증가 합 니 다

  • 4.567917.절대:색인 에 따라 Buffer 에 데 이 터 를 직접 읽 고 쓰기 때문에 position 의 위 치 를 바 꾸 지 않 습 니 다.다음은 Buffer 의 테스트 클래스 입 니 다.Buffer 대상 이 데 이 터 를 만 들 고 읽 는 과정 에서 position,limit,capacity 의 변 화 를 검증 하 는 데 사 용 됩 니 다.
    package com.zhyea.newio;
    
    
    
    import java.nio.CharBuffer;
    
    
    
    /**
    
     * java IOBuffer   
    
     * @author robin
    
     *
    
     */
    
    public class BufferTest {
    
    
    
        public static void main(String[] args) {
    
            CharBuffer buff = CharBuffer.allocate(16);
    
            System.out.println("    :" 
    
                             + " capacity:" + buff.capacity() 
    
                             + " position:"+buff.position() 
    
                             + " limit:"+buff.limit());
    
            buff.put('a').put('b').put('c').put(new char[]{'d', 'e', 'f'});
    
            System.out.println("  6    :" 
    
                     + " capacity:" + buff.capacity() 
    
                     + " position:"+buff.position() 
    
                     + " limit:"+buff.limit());
    
            buff.flip();
    
            System.out.println("  flip   :" 
    
                     + " capacity:" + buff.capacity() 
    
                     + " position:"+buff.position() 
    
                     + " limit:"+buff.limit());
    
            buff.get();
    
            System.out.println("        :" 
    
                     + " capacity:" + buff.capacity() 
    
                     + " position:"+buff.position() 
    
                     + " limit:"+buff.limit());
    
            buff.clear();
    
            System.out.println("  clear   :" 
    
                     + " capacity:" + buff.capacity() 
    
                     + " position:"+buff.position() 
    
                     + " limit:"+buff.limit());
    
            buff.get(3);
    
            System.out.println("       :" 
    
                     + " capacity:" + buff.capacity() 
    
                     + " position:"+buff.position() 
    
                     + " limit:"+buff.limit());
    
        }
    
    
    
    }

    allocate 방법 으로 만 든 Buffer 는 일반 Buffer 이지 만 ByteBuffer 는 allocate Direct 방법(ByteBuffer 만 제공)을 제공 하여 직접 Buffer 를 만 들 었 습 니 다.직접 Buffer 를 만 드 는 비용 이 비교적 높 지만 운영 할 때 환경 이 이 Buffer 에서 비교적 빠 른 본 기계 IO 작업 을 할 수 있 습 니 다.창설 원가 가 비교적 높 기 때문에 직접 버 퍼 는 긴 생존 기간 의 버 퍼 에 더욱 적합 하 며,짧 은 생존 기간 에 사용 하기 만 하면 버 리 는 버 퍼 에 적용 되 지 않 는 다.직접 버 퍼 는 일반 버 퍼 와 다 르 지 않다.채널 의 사용 채널 은 전통 적 인 흐름 대상 과 유사 하지만 이에 비해 채널 은 두 가지 주요 한 차이 가 있다
  • Channel 은 지정 한 파일 의 일부 또는 전 부 를 Buffer 로 직접 표시 할 수 있 습 니 다
  • 프로그램 은 채널 의 데 이 터 를 직접 읽 을 수 없고 Buffer 를 통 해 진행 해 야 합 니 다.Channel 은 자바.nio.channels 패키지 에 있 는 인터페이스 로 시스템 은 이 인터페이스 에 DataGramChannel,FileChannel,Pipe.inkChannel,Pipe.SourceChannel 등 실현 클래스 를 제공 합 니 다.채널 의 이름 을 보면 새 IO 에서 채널 은 기능 에 따라 구분 된다.Channel 은 구조 기 를 통 해 직접 만 들 지 말고 전통 적 인 노드 인 InputStream,OutputStream 의 getChannel 방법 으로 대응 하 는 Channel 을 되 돌려 야 합 니 다.서로 다른 노드 가 돌아 오 는 Channel 은 다 릅 니 다.예 를 들 어 FileInputStream 의 getChannel 은 FileChannel 을 되 돌려 주 고 PipedInputStream 은 Pipe.inkChannel 을 되 돌려 줍 니 다.Channel 에서 가장 자주 사용 하 는 세 가지 방법 은 map,read 와 write 입 니 다.그 중에서 map 방법 은 Channel 에 대응 하 는 부분 이나 모든 데 이 터 를 ByteBuffer 로 표시 하 는 데 사 용 됩 니 다.read,write 방법 은 Buffer 에서 데 이 터 를 읽 거나 기록 하 는 데 사 용 됩 니 다.FileChannel 읽 기와 쓰기 예제:
    package com.zhyea.newio;
    
    
    
    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.FileOutputStream;
    
    import java.io.IOException;
    
    import java.nio.CharBuffer;
    
    import java.nio.MappedByteBuffer;
    
    import java.nio.channels.FileChannel;
    
    import java.nio.channels.FileChannel.MapMode;
    
    import java.nio.charset.Charset;
    
    import java.nio.charset.CharsetDecoder;
    
    
    
    /**
    
     * Channel   。  Channel A        B  
    
     * 
    
     * @author robin
    
     *
    
     */
    
    public class FileChannelTest {
    
    
    
        public static void main(String[] args) {
    
            FileChannel in = null;
    
            FileChannel out = null;
    
    
    
            try {
    
                String fileAPath = "D:\\a.txt";
    
                String fileBPath = "D:\\b.txt";
    
                File file = new File(fileAPath);
    
                
    
                in = new FileInputStream(file).getChannel();
    
                MappedByteBuffer buffer = in.map(MapMode.READ_ONLY, 0, file.length());
    
                
    
                out = new FileOutputStream(fileBPath).getChannel();
    
                out.write(buffer);
    
                buffer.clear();
    
                
    
                Charset charset = Charset.forName("GBK");
    
                CharsetDecoder decoder = charset.newDecoder();
    
                CharBuffer charBuffer = decoder.decode(buffer);
    
                
    
                System.out.println(charBuffer);
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            } finally {
    
                try {
    
                    if (null != in)
    
                        in.close();
    
                    if (null != out)
    
                        out.close();
    
                } catch (IOException e) {
    
                    e.printStackTrace();
    
                }
    
            }
    
        }
    
    
    
    }

    RandomAccessFile 은 채널 인 스 턴 스 에 대응 하여 클래스 텍스트 파일 의 추가 구현:
    package com.zhyea.newio;
    
    
    
    import java.io.File;
    
    import java.io.IOException;
    
    import java.io.RandomAccessFile;
    
    import java.nio.ByteBuffer;
    
    import java.nio.channels.FileChannel;
    
    import java.nio.channels.FileChannel.MapMode;
    
    
    
    public class RandomFileChannelTest {
    
        
    
        public static void main(String[] args) {
    
            FileChannel randomChannel = null;
    
    
    
            try {
    
                String fileBPath = "D:\\b.txt";
    
                File file = new File(fileBPath);
    
                
    
                randomChannel = new RandomAccessFile(file, "rw").getChannel();
    
                ByteBuffer buffer = randomChannel.map(MapMode.READ_ONLY, 0, file.length());
    
                randomChannel.position(file.length());
    
                
    
                randomChannel.write(buffer);
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            } finally {
    
                try {
    
                    if (null != randomChannel)
    
                                    randomChannel.close();
    
                } catch (IOException e) {
    
                    e.printStackTrace();
    
                }
    
            }
    
        }
    
        
    
    }

    채널 테스트,버퍼 읽 기 데이터 구현:
    package com.zhyea.newio;
    
    
    
    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.FileOutputStream;
    
    import java.io.IOException;
    
    import java.nio.ByteBuffer;
    
    import java.nio.CharBuffer;
    
    import java.nio.channels.FileChannel;
    
    import java.nio.charset.Charset;
    
    import java.nio.charset.CharsetDecoder;
    
    
    
    public class ChannelTest {
    
        public static void main(String[] args) {
    
            FileChannel in = null;
    
            FileChannel out = null;
    
    
    
            try {
    
                String fileAPath = "D:\\a.txt";
    
                String fileBPath = "D:\\b.txt";
    
                File file = new File(fileAPath);
    
                
    
                in = new FileInputStream(file).getChannel();
    
                
    
                out = new FileOutputStream(fileBPath).getChannel();
    
                
    
                ByteBuffer buffer = ByteBuffer.allocate(16);
    
                while(in.read(buffer) != -1){
    
                    buffer.flip();
    
    
    
                    Charset charset = Charset.forName("GBK");
    
                    CharsetDecoder decoder = charset.newDecoder();
    
                    CharBuffer charBuffer = decoder.decode(buffer);
    
                    
    
                    System.out.println(charBuffer);
    
                    
    
                    buffer.position(0);
    
                    out.write(buffer);
    
                    
    
                    buffer.clear();
    
                }
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            } finally {
    
                try {
    
                    if (null != in)
    
                        in.close();
    
                    if (null != out)
    
                        out.close();
    
                } catch (IOException e) {
    
                    e.printStackTrace();
    
                }
    
            }
    
    
    
        }
    
    }

    Charset 에서 컴퓨터 기록 파일 을 사용 하 는 것 은 모두 기 록 된 바이트 시퀀스 입 니 다.기 록 된 바이트 시퀀스 를 정확하게 보 여주 고 사용 하려 면 적당 한 문자 집합 을 사용 하여 디 코딩 해 야 합 니 다.자바 의 인 코딩 은 유 니 코드 문자 집합 을 사용 합 니 다.읽 은 파일 인 코딩 형식 이 유 니 코드 가 아니면 오류 가 발생 합 니 다.자바 는 바이트 시퀀스 와 문자열 간 의 변환 관 계 를 처리 하기 위해 Charset 를 제공 합 니 다.Charset 는 인 코딩 과 디 코딩 방법 을 제공 하고 Charset 가 지원 하 는 문자 집합 을 가 져 오 는 방법 도 제공 합 니 다.Charset 클래스 는 가 변 적 이지 않 습 니 다.Charset 는 현재 JDK 가 지원 하 는 모든 문자 집합 을 가 져 오 는 availableCharset()정적 방법 을 제공 합 니 다.데모 코드 는 다음 과 같 습 니 다.
    package com.zhyea.newio;
    
    
    
    import java.nio.charset.Charset;
    
    import java.util.Map;
    
    
    
    public class CharsetTest {
    
    
    
        public static void main(String[] args){
    
            listCharset();
    
        }
    
        
    
        public static void listCharset(){
    
            Map<String, Charset> map = Charset.availableCharsets();
    
            for(String tmp : map.keySet()){
    
                System.out.println(tmp + " ----------> " + map.get(tmp));
    
            }
    
        }
    
    }

    출력 결과 가 매우 많아 서 내 기계 에서 시험 해 보 았 는데 모두 169 줄 이 었 다.흥미 가 있 으 면 한번 해 볼 만하 지만,여 기 는 열거 하지 않 겠 다.문자 집합 이름 을 알 게 되면 Charset 의 forName()방법 으로 Charset 대상 을 만 들 수 있 습 니 다.코드 는 다음 과 같 습 니 다.
    Charset charset = Charset.forName("UTF-8");

    Charset 대상 을 얻 으 면 Charset 대상 의 new Decoder()와 new Encoder()방법 으로 각각 CharsetEncoder 와 CharsetDecoder 대상 을 만 들 수 있 습 니 다.이 두 가 지 는 각각 Charset 의 인 코더 와 디코더 이다.그들 을 사용 하면 바이트 시퀀스 와 문자열 의 상호 변환 을 실현 할 수 있다.디 코딩 작업 만 완료 하기 위해 서 라면 Charset 대상 의 encode()와 decode()방법 을 직접 사용 할 수 있 습 니 다.평소에 검사 문자열 인 코딩 과 같은 요 구 를 만 날 수 있 습 니 다.이것 은 Charset 를 사용 하여 테스트 클래스 를 실현 하 는 것 을 고려 할 수 있 습 니 다.
    package com.zhyea.newio;
    
    
    
    import java.nio.ByteBuffer;
    
    import java.nio.charset.Charset;
    
    
    
    public class CharsetTest {
    
    
    
        public static void main(String[] args) {
    
            String str = "      ";
    
            System.out.println(checkEncoding(str));
    
        }
    
    
    
        public static String checkEncoding(String str) {
    
            String tmp;
    
            for (Encode e : Encode.values()) {
    
                ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
    
                tmp = Charset.forName(e.getValue()).decode(buffer).toString();
    
                if (str.equals(tmp)) {
    
                    return e.getValue();
    
                }
    
            }
    
            return null;
    
        }
    
    
    
        enum Encode {
    
            GBK("GBK"), UTF8("UTF-8"), BIG5("BIG5"), ISO88591("ISO-8859-1");
    
    
    
            private String value;
    
    
    
            Encode(String val) {
    
                this.value = val;
    
            }
    
    
    
            public String getValue() {
    
                return this.value;
    
            }
    
        }
    
    }


  • 테스트 클래스 에 문자 집합 인 코딩 을 기록 하기 위해 매 거 진 클래스 를 만 들 었 습 니 다.테스트 에 사용 할 문자열 은 직접 쓴 문자열 로 이 컴퓨터 의 작업 공간 인 코딩 형식 과 같 습 니 다.
    선택 기 사용
    Selector 는 주로 비 차단 Socket 통신 에 사 용 됩 니 다.이에 맞 춰 선택 가능 채널 을 사용 합 니 다.
    Selectable Channel 은 IO 작업 을 막 지 않 는 Channel 대상 을 지원 할 수 있 으 며,register()방법 으로 지정 한 Selector 에 등록 할 수 있 습 니 다.이러한 등록 관 계 는 SelectionKey 인 스 턴 스 로 표 시 됩 니 다.selector 대상 은 select()방법 을 제공 합 니 다.이 방법 은 프로그램 이 여러 개의 IO 채널 을 동시에 감시 할 수 있 도록 합 니 다.
    Selectable Channel 대상 은 차단 과 비 차단 두 가지 모드 를 지원 합 니 다(모든 채널 은 기본적으로 차단 모드 입 니 다).SeletableChannel 은 채널 의 모드 상 태 를 설정 하고 되 돌려 주 는 두 가지 방법 을 제공 합 니 다.
  • SelectableChannel configureBlocking(boolean block):차단 모드 를 사용 할 지 설정 합 니 다
  • boolean isBlocking():이 채널 이 차단 모드 인지 되 돌려 줍 니 다
  • 좋은 웹페이지 즐겨찾기