programing

중첩된 각 Output Stream과 Writer를 개별적으로 닫아야 합니까?

firstcheck 2022. 11. 27. 19:57
반응형

중첩된 각 Output Stream과 Writer를 개별적으로 닫아야 합니까?

코드를 쓰고 있습니다.

OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(gzipOutputStream));

다음과 같이 모든 스트림 또는 라이터를 닫아야 합니까?

gzipOutputStream.close();
bw.close();
outputStream.close();

아니면 마지막 스트림을 닫아도 될까요?

bw.close();

하고, 네,만 하면 .bw이러한 스트림 구현에는 문제가 없지만, 이는 큰 가정입니다.

예외를 발생시키는 후속 스트림을 구성하는 문제가 이전 스트림을 중단하지 않도록 리소스 사용(튜토리얼)을 사용합니다.따라서 기본 스트림을 종료하기 위한 호출을 스트림 구현에 의존할 필요가 없습니다.

try (
    OutputStream outputStream = new FileOutputStream(createdFile);
    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
    OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
    BufferedWriter bw = new BufferedWriter(osw)
    ) {
    // ...
}

「 」는, 「 」에 콜 된 것에 해 주세요.close★★★★★★★★★★★★★★★★★★.

중요사항:리소스 시도에서 닫히려면 변수를 열 때 스트림을 변수에 할당해야 합니다. 네스팅을 사용할 수 없습니다.nesting을 사용하는 경우 이후의 스트림 중 하나를 구성할 때 예외가 발생합니다(예:GZIPOutputStream)는, 네스트 된 콜에 의해서 작성된 스트림을 열어 둡니다.JLS © 14.20.3부터:

리소스 사용 문은 변수(리소스라고 함)를 사용하여 매개 변수화되며, 변수(리소스라고 함)는 다음 명령어를 실행하기 전에 초기화됩니다.try 후 역순으로 .기된된 、 행행후후후try

"변수"라는 단어에 주목하십시오(강조점).

예: 이 작업을 수행하지 마십시오.

// DON'T DO THIS
try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(
        new GZIPOutputStream(
        new FileOutputStream(createdFile))))) {
    // ...
}

...컨스트럭터로부터의 예외(이 예외는 던질 수 있습니다)IOExceptionFileOutputStream오픈. 어떤 리소스는 던질 수 있는 컨스트럭터를 가지고 있고 어떤 리소스는 가지고 있지 않기 때문에 그것들을 따로 나열하는 것은 좋은 습관입니다.

이 프로그램으로 JLS 섹션의 해석을 재확인할 수 있습니다.

public class Example {

    private static class InnerMost implements AutoCloseable {
        public InnerMost() throws Exception {
            System.out.println("Constructing " + this.getClass().getName());
        }

        @Override
        public void close() throws Exception {
            System.out.println(this.getClass().getName() + " closed");
        }
    }

    private static class Middle implements AutoCloseable {
        private AutoCloseable c;

        public Middle(AutoCloseable c) {
            System.out.println("Constructing " + this.getClass().getName());
            this.c = c;
        }

        @Override
        public void close() throws Exception {
            System.out.println(this.getClass().getName() + " closed");
            c.close();
        }
    }

    private static class OuterMost implements AutoCloseable {
        private AutoCloseable c;

        public OuterMost(AutoCloseable c) throws Exception {
            System.out.println("Constructing " + this.getClass().getName());
            throw new Exception(this.getClass().getName() + " failed");
        }

        @Override
        public void close() throws Exception {
            System.out.println(this.getClass().getName() + " closed");
            c.close();
        }
    }

    public static final void main(String[] args) {
        // DON'T DO THIS
        try (OuterMost om = new OuterMost(
                new Middle(
                    new InnerMost()
                    )
                )
            ) {
            System.out.println("In try block");
        }
        catch (Exception e) {
            System.out.println("In catch block");
        }
        finally {
            System.out.println("In finally block");
        }
        System.out.println("At end of main");
    }
}

...이 출력은 다음과 같습니다.

예시$의 작성내부 모스트예제 $중간 구성구성 예$OuterMost캐치블록 내최종 블록 내메인 종료 시

「」에의 콜은 것에 해 주세요.closecontract.discontracts.

★★★를 main:

public static final void main(String[] args) {
    try (
        InnerMost im = new InnerMost();
        Middle m = new Middle(im);
        OuterMost om = new OuterMost(m)
        ) {
        System.out.println("In try block");
    }
    catch (Exception e) {
        System.out.println("In catch block");
    }
    finally {
        System.out.println("In finally block");
    }
    System.out.println("At end of main");
}

적절한 수 있습니다.close 삭제:

예시$의 작성내부 모스트예제 $중간 구성구성 예$OuterMost예$중간폐쇄예 $InnerMost가 닫힘예 $InnerMost가 닫힘캐치블록 내최종 블록 내메인 종료 시

두 번 콜을 (으, 2번 합니다.InnerMost#close,Middle는 리소스 사용 Recommendications 사용 시도)입니다

대부분의 외부 스트림을 닫을 수 있습니다. 실제로 랩된 모든 스트림을 유지할 필요는 없으며 Java 7 리소스 시도 기능을 사용할 수 있습니다.

try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                     new GZIPOutputStream(new FileOutputStream(createdFile)))) {
     // write to the buffered writer
}

YAGNI(You-int-gonna-need-it)에 가입하는 경우 실제로 필요한 코드만 추가해야 합니다.필요한 코드를 추가해서는 안 되지만 실제로는 도움이 되지 않습니다.

이 예를 들어, 이렇게 하지 않으면 어떤 문제가 발생할 수 있고 어떤 영향이 있을지 상상해 보십시오.

try (
    OutputStream outputStream = new FileOutputStream(createdFile);
    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
    OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
    BufferedWriter bw = new BufferedWriter(osw)
    ) {
    // ...
}

FileOutputStream을 하겠습니다.open든든 、 을을일일일도 。

/**
 * Opens a file, with the specified name, for overwriting or appending.
 * @param name name of file to be opened
 * @param append whether the file is to be opened in append mode
 */
private native void open(String name, boolean append)
    throws FileNotFoundException;

파일을 찾을 수 없는 경우 닫을 기본 리소스가 없으므로 파일을 닫아도 아무런 차이가 없습니다.파일이 존재하는 경우 FileNotFoundException을 던져야 합니다.따라서 이 라인에서만 리소스를 닫으려고 해도 아무런 이점이 없습니다.

파일을 닫아야 하는 이유는 파일을 정상적으로 열었지만 나중에 오류가 발생할 경우입니다.

다음 을 볼까요?GZIPOutputStream

예외를 발생시킬 수 있는 코드가 있습니다.

private void writeHeader() throws IOException {
    out.write(new byte[] {
                  (byte) GZIP_MAGIC,        // Magic number (short)
                  (byte)(GZIP_MAGIC >> 8),  // Magic number (short)
                  Deflater.DEFLATED,        // Compression method (CM)
                  0,                        // Flags (FLG)
                  0,                        // Modification time MTIME (int)
                  0,                        // Modification time MTIME (int)
                  0,                        // Modification time MTIME (int)
                  0,                        // Modification time MTIME (int)
                  0,                        // Extra flags (XFLG)
                  0                         // Operating system (OS)
              });
}

그러면 파일의 헤더가 기록됩니다.쓰기 위해 파일을 열 수 있지만 8바이트도 쓸 수 없는 것은 매우 드문 일이지만, 이런 일이 발생할 수 있고 그 후에는 닫지 않습니다.파일이 닫히지 않으면 어떻게 됩니까?

플러시되지 않은 쓰기는 수신되지 않고 폐기됩니다.이 경우 스트림에 정상적으로 입력된 바이트는 이 시점에서 버퍼링되지 않습니다.그러나 닫히지 않은 파일은 영원히 존속하지 않습니다.대신 FileOutputStream은

protected void finalize() throws IOException {
    if (fd != null) {
        if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
            flush();
        } else {
            /* if fd is shared, the references in FileDescriptor
             * will ensure that finalizer is only called when
             * safe to do so. All references using the fd have
             * become unreachable. We can call close()
             */
            close();
        }
    }
}

파일을 전혀 닫지 않으면 즉시 닫히지 않습니다(또한 말씀드렸듯이 버퍼에 남아 있는 데이터는 이렇게 손실되지만 이 시점에는 없습니다).

파일을 즉시 닫지 않으면 어떤 결과가 초래됩니까?정상적인 상황에서는 일부 데이터가 손실될 수 있으며 파일 설명자가 부족할 수 있습니다.그러나 파일을 작성할 수 있지만 쓸 수 없는 시스템이 있다면 더 큰 문제가 발생합니다.즉, 실패하더라도 이 파일을 반복적으로 작성하려고 하는 이유를 상상하기 어렵습니다.

OutputStreamWriter와 BufferedWriter는 모두 IOException을 컨스트럭터에 넣지 않기 때문에 어떤 문제가 발생하는지 명확하지 않습니다.BufferedWriter의 경우 Out Of Memory Error가 발생할 수 있습니다.이 경우 GC가 즉시 트리거되며 앞에서 설명한 바와 같이 파일이 닫힙니다.

모든 스트림이 인스턴스화된 경우 가장 바깥쪽만 닫으면 됩니다.

인터페이스의 메뉴얼에는, 다음의 방법으로 종료한다고 기재되어 있습니다.

이 스트림을 닫고 관련된 시스템리소스를 해방합니다.

릴리스 시스템 리소스에는 닫힘 스트림이 포함됩니다.

또, 다음과 같이 기술되어 있습니다.

스트림이 이미 닫혀 있는 경우 이 메서드를 호출해도 효과가 없습니다.

따라서 나중에 명시적으로 닫으면 문제가 발생하지 않습니다.

차라리 사용하는게 낫겠다.try(...)구문(Java 7). 예를 들어,

try (OutputStream outputStream = new FileOutputStream(createdFile)) {
      ...
}

마지막 스트림만 닫으면 됩니다. 종료 콜은 기본 스트림에도 전송됩니다.

아니요, 최상위 수준입니다.Stream또는reader모든 기본 스트림/리더가 닫힙니다.

체크하다close()최상위 스트림의 메서드 구현.

Java 7 에서는, 자원에 의한 기능 시행이 있습니다.스트림을 명시적으로 닫을 필요는 없습니다.그것은 처리됩니다.

언급URL : https://stackoverflow.com/questions/28276423/is-it-necessary-to-close-each-nested-outputstream-and-writer-separately

반응형