development

Java InputStream의 내용을 OutputStream에 작성하는 쉬운 방법

big-blog 2020. 2. 19. 22:07
반응형

Java InputStream의 내용을 OutputStream에 작성하는 쉬운 방법


나는 내가의 내용을 쓸 수있는 간단한 방법을 추적 할 수 없다는 것을 오늘 발견 놀랐습니다 InputStreamOutputStream자바를. 분명히 바이트 버퍼 코드를 작성하는 것은 어렵지 않지만 인생을 더 쉽게 (그리고 코드를 더 명확하게) 만들 수있는 것이 빠져 있다고 생각합니다.

따라서 InputStream inand가 주어지면 OutputStream out다음을 작성하는 더 간단한 방법이 있습니까?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}

자바 9

Java 9부터 다음 서명으로 InputStream호출되는 메소드를 제공합니다 transferTo.

public long transferTo(OutputStream out) throws IOException

현상태대로 문서의 상태, transferTo것입니다 :

이 입력 스트림로부터 모든 바이트를 읽고, 읽은 순서대로 지정된 출력 스트림에 바이트를 기입합니다. 돌아 왔을 때,이 입력 스트림은 스트림의 말미에 있습니다. 이 방법은 스트림을 닫지 않습니다.

이 방법은 입력 스트림에서 무한히 읽거나 출력 스트림에 쓰는 것을 차단할 수 있습니다. 입력 및 / 또는 출력 스트림이 비동기 적으로 닫히거나 전송 중에 스레드가 중단 된 경우의 동작은 입력 및 출력 스트림에 따라 달라 지므로 지정되지 않습니다.

그래서 자바의 내용을 쓰기 위해 InputStream에를 OutputStream, 당신은 쓸 수 있습니다 :

input.transferTo(output);

WMR에서 언급했듯이 org.apache.commons.io.IOUtilsApache에는 copy(InputStream,OutputStream)원하는 것을 정확하게 수행 하는 메소드 가 있습니다.

따라서, 당신은 :

InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();

... 당신의 코드에서.

피해야 할 이유가 IOUtils있습니까?


Java 7을 사용하는 경우 표준 라이브러리의 파일 이 가장 좋은 방법입니다.

/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)

편집 : 물론 파일에서 InputStream 또는 OutputStream 중 하나를 만들 때 유용합니다. file.toPath()파일에서 경로를 얻는 데 사용 합니다.

기존 파일 (예 :로 만든 파일)에 쓰려면 복사 옵션 File.createTempFile()을 전달해야합니다 REPLACE_EXISTING(그렇지 않으면 FileAlreadyExistsExceptionthrow 됨).

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)

나는 이것이 효과가 있다고 생각하지만 그것을 테스트해야합니다 ... 사소한 "개선"이지만 가독성에 약간의 비용이들 수 있습니다.

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}

구아바 사용 ByteStreams.copy():

ByteStreams.copy(inputStream, outputStream);

간단한 기능

당신이 단지를 작성이 필요하면 InputStreamA와 File당신은이 간단한 기능을 사용할 수 있습니다 :

private void copyInputStreamToFile( InputStream in, File file ) {
    try {
        OutputStream out = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int len;
        while((len=in.read(buf))>0){
            out.write(buf,0,len);
        }
        out.close();
        in.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

PipedInputStream그리고 PipedOutputStream여러 스레드가있는 경우로서 만 사용되어야 Javadoc을 지적한 .

또한 입력 스트림과 출력 스트림은 스레드 중단을 IOExceptions로 감싸지 않습니다 . 따라서 코드에 중단 정책을 통합하는 것을 고려해야합니다.

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
    if (Thread.interrupted()) {
        throw new InterruptedException();
    }
}

이 API를 사용하여 많은 양의 데이터를 복사하거나 오랫동안 견딜 수없는 스트림의 데이터를 복사하려는 경우 유용한 추가 기능입니다.


JDK(아마 어떤 다른 어쨌든하지 않음) 어설픈 타사 라이브러리 없이는 "쉬운"방법이없는 것처럼 사용하는 동일한 코드 보인다 있도록. 다음에서 직접 복사됩니다 java.nio.file.Files.java.

// buffer size used for reading and writing
    private static final int BUFFER_SIZE = 8192;

/**
     * Reads all bytes from an input stream and writes them to an output stream.
     */
    private static long copy(InputStream source, OutputStream sink)
        throws IOException
    {
        long nread = 0L;
        byte[] buf = new byte[BUFFER_SIZE];
        int n;
        while ((n = source.read(buf)) > 0) {
            sink.write(buf, 0, n);
            nread += n;
        }
        return nread;
    }

Spring 프레임 워크 를 사용하는 사람들에게는 유용한 StreamUtils 클래스가 있습니다.

StreamUtils.copy(in, out);

위의 스트림을 닫지 않습니다. 복사 후 스트림을 닫으려면 FileCopyUtils 클래스를 대신 사용하십시오.

FileCopyUtils.copy(in, out);

JDK 방법 으로이 작업을 훨씬 쉽게 수행 할 수있는 방법은 없지만 Apocalisp가 이미 언급 했듯이이 아이디어를 가진 유일한 사람은 아닙니다 .Jakarta Commons IO의 IOUtils사용할 수 있으며 다른 유용한 것들도 많이 있습니다. IMO는 실제로 JDK의 일부 여야합니다.


Java7 및 try-with-resources 를 사용하면 간단하고 읽기 쉬운 버전이 제공됩니다.

    try(InputStream inputStream     =   new FileInputStream("C:\\mov.mp4");
        OutputStream outputStream   =   new FileOutputStream("D:\\mov.mp4")){

        byte[] buffer    =   new byte[10*1024];

        for (int length; (length = inputStream.read(buffer)) != -1; ){
            outputStream.write(buffer, 0, length);
        }

    }catch (FileNotFoundException exception){
        exception.printStackTrace();
    }catch (IOException ioException){
        ioException.printStackTrace();
    }

다음은 가장 간단한 for 루프로 수행하는 방법입니다.

private void copy(final InputStream in, final OutputStream out)
    throws IOException {
    final byte[] b = new byte[8192];
    for (int r; (r = in.read(b)) != -1;) {
        out.write(b, 0, r);
    }
}

Commons Net의 Util 클래스를 사용하십시오.

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);

IMHO보다 작은 스 니펫 (길이 변수의 범위가 좁아짐) :

byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
    out.write(buffer, 0, n);

부수적으로, 나는 더 많은 사람들이 왜 for루프를 사용하지 않는지 이해하지 못하고 , 대신에 while"가난한"스타일로 간주되는 어사 인 앤 테스트 식을 선택합니다.


대부분의 파일이 1024 바이트보다 크기 때문에 큰 버퍼를 사용하는 것이 좋습니다. 또한 읽기 바이트 수를 양수로 확인하는 것이 좋습니다.

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();

PipedInputStream 및 PipedOutputStream은 서로 연결할 수 있으므로 유용 할 수 있습니다.


가능한 다른 후보는 Guava I / O 유틸리티입니다.

http://code.google.com/p/guava-libraries/wiki/IOExplained

Guava가 하나의 함수에 다른 라이브러리를 추가하는 대신 이미 프로젝트에서 상당히 유용하기 때문에 이것을 사용할 것이라고 생각했습니다.


코드에서 버퍼링 의미를 사용 BufferedInputStream하고 BufferedOutputStream제거합니다.

try (OutputStream out = new BufferedOutputStream(...);
     InputStream in   = new BufferedInputStream(...))) {
  int ch;
  while ((ch = in.read()) != -1) {
    out.write(ch);
  }
}

이것은 내 최고의 샷입니다!

그리고 inputStream.transferTo(...)너무 일반적이기 때문에 사용하지 마십시오 . 버퍼 메모리를 제어하면 코드 성능이 향상됩니다.

public static void transfer(InputStream in, OutputStream out, int buffer) throws IOException {
    byte[] read = new byte[buffer]; // Your buffer size.
    while (0 < (buffer = in.read(read)))
        out.write(read, 0, buffer);
}

스트림의 크기를 미리 알면이 (개선 가능한) 방법으로 사용합니다.

public static void transfer(int size, InputStream in, OutputStream out) throws IOException {
    transfer(in, out,
            size > 0xFFFF ? 0xFFFF // 16bits 65,536
                    : size > 0xFFF ? 0xFFF// 12bits 4096
                            : size < 0xFF ? 0xFF // 8bits 256
                                    : size
    );
}

public static boolean copyFile(InputStream inputStream, OutputStream out) {
    byte buf[] = new byte[1024];
    int len;
    long startTime=System.currentTimeMillis();

    try {
        while ((len = inputStream.read(buf)) != -1) {
            out.write(buf, 0, len);
        }

        long endTime=System.currentTimeMillis()-startTime;
        Log.v("","Time taken to transfer all bytes is : "+endTime);
        out.close();
        inputStream.close();

    } catch (IOException e) {

        return false;
    }
    return true;
}

Cactoos 사용해 보기 :

new LengthOf(new TeeInput(input, output)).value();

자세한 내용은 여기 : http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html


이 방법을 사용할 수 있습니다

public static void copyStream(InputStream is, OutputStream os)
 {
     final int buffer_size=1024;
     try
     {
         byte[] bytes=new byte[buffer_size];
         for(;;)
         {
           int count=is.read(bytes, 0, buffer_size);
           if(count==-1)
               break;
           os.write(bytes, 0, count);
         }
     }
     catch(Exception ex){}
 }

참고 URL : https://stackoverflow.com/questions/43157/easy-way-to-write-contents-of-a-java-inputstream-to-an-outputstream



반응형