Introdução ao StreamUtils da Spring

Introdução ao StreamUtils da Spring

1. Visão geral

Neste artigo, daremos uma olhada na classeStreamUtils e como podemos usá-la.

Simplificando,StreamUtils é uma classe do Spring que contém alguns métodos utilitários para lidar com o fluxo -InputStreameOutputStream que residem no pacotejava.io e não relacionados ao Java 8 API Stream.

2. Dependência do Maven

A classeStreamUtils está disponível no módulo spring-core, então vamos adicioná-la ao nossopom.xml:


    org.springframework
    spring-core
    5.1.4.RELEASE

Você pode encontrar a versão mais recente da biblioteca emMaven Central Repository.

3. Copiando Streams

A classeStreamUtils contém vários métodos sobrecarregados chamadoscopy(), bem como algumas outras variações:

  • copyRange ()

  • copyToByteArray ()

  • copyString ()

Podemos copiar fluxos sem usar nenhuma biblioteca. No entanto, o código será complicado e muito mais difícil de ler e entender.

Observe que estamos omitindo o fechamento de streams por uma questão de simplicidade.

Vamos ver como podemos copiar o conteúdo de umInputStream para um determinadoOutputStream:

@Test
public void whenCopyInputStreamToOutputStream_thenCorrect() throws IOException {
    String inputFileName = "src/test/resources/input.txt";
    String outputFileName = "src/test/resources/output.txt";
    File outputFile = new File(outputFileName);
    InputStream in = new FileInputStream(inputFileName);
    OutputStream out = new FileOutputStream(outputFile);

    StreamUtils.copy(in, out);

    assertTrue(outputFile.exists());
    String inputFileContent = getStringFromInputStream(new FileInputStream(inputFileName));
    String outputFileContent = getStringFromInputStream(new FileInputStream(outputFileName));
    assertEquals(inputFileContent, outputFileContent);
}

O arquivo criado contém o conteúdo deInputStream.

Observe quegetStringFromInputStream() é um método que pegaInputStreame retorna seu conteúdo comoString. A implementação do método está disponível na versão completa do código.

Não temos que copiar todo o conteúdo deInputStream, podemos copiar uma faixa do conteúdo para um determinadoOutputStream usando o métodocopyRange():

@Test
public void whenCopyRangeOfInputStreamToOutputStream_thenCorrect() throws IOException {
    String inputFileName = "src/test/resources/input.txt";
    String outputFileName = "src/test/resources/output.txt";
    File outputFile = new File(outputFileName);
    InputStream in = new FileInputStream(inputFileName);
    OutputStream out = new FileOutputStream(outputFileName);

    StreamUtils.copyRange(in, out, 1, 10);

    assertTrue(outputFile.exists());
    String inputFileContent = getStringFromInputStream(new FileInputStream(inputFileName));
    String outputFileContent = getStringFromInputStream(new FileInputStream(outputFileName));

    assertEquals(inputFileContent.substring(1, 11), outputFileContent);
}

Como podemos ver aqui, ocopyRange() leva quatro parâmetros, oInputStream, oOutputStream, a posição para começar a copiar e a posição para terminar a cópia. Mas e se o intervalo especificado exceder o comprimento deInputStream? O métodocopyRange() então copia até o final do fluxo.

Vamos ver como podemos copiar o conteúdo de umString para um determinadoOutputStream:

@Test
public void whenCopyStringToOutputStream_thenCorrect() throws IOException {
    String string = "Should be copied to OutputStream.";
    String outputFileName = "src/test/resources/output.txt";
    File outputFile = new File(outputFileName);
    OutputStream out = new FileOutputStream("src/test/resources/output.txt");

    StreamUtils.copy(string, StandardCharsets.UTF_8, out);

    assertTrue(outputFile.exists());

    String outputFileContent = getStringFromInputStream(new FileInputStream(outputFileName));

    assertEquals(outputFileContent, string);
}

O métodocopy() usa três parâmetros - oString a ser copiado, oCharset que queremos usar para gravar no arquivo e oOutputStream que queremos copiar o conteúdo deString para.

Aqui está como podemos copiar o conteúdo de um determinadoInputStream para um novoString:

@Test
public void whenCopyInputStreamToString_thenCorrect() throws IOException {
    String inputFileName = "src/test/resources/input.txt";
    InputStream is = new FileInputStream(inputFileName);
    String content = StreamUtils.copyToString(is, StandardCharsets.UTF_8);

    String inputFileContent = getStringFromInputStream(new FileInputStream(inputFileName));
    assertEquals(inputFileContent, content);
}

Também podemos copiar o conteúdo de uma determinada matriz de bytes para umOutputStream:

public void whenCopyByteArrayToOutputStream_thenCorrect() throws IOException {
    String outputFileName = "src/test/resources/output.txt";
    String string = "Should be copied to OutputStream.";
    byte[] byteArray = string.getBytes();
    OutputStream out = new FileOutputStream("src/test/resources/output.txt");

    StreamUtils.copy(byteArray, out);

    String outputFileContent = getStringFromInputStream(new FileInputStream(outputFileName));

    assertEquals(outputFileContent, string);
}

Ou podemos copiar o conteúdo de um determinadoInputStream em uma nova matriz de bytes:

public void whenCopyInputStreamToByteArray_thenCorrect() throws IOException {
    String inputFileName = "src/test/resources/input.txt";
    InputStream is = new FileInputStream(inputFileName);
    byte[] out = StreamUtils.copyToByteArray(is);

    String content = new String(out);
    String inputFileContent = getStringFromInputStream(new FileInputStream(inputFileName));

    assertEquals(inputFileContent, content);
}

4. Outra Funcionalidade

UmInputStream pode ser passado como um argumento para o métododrain() para remover todos os dados restantes no fluxo:

StreamUtils.drain(in);

Também podemos usar o métodoemptyInput() para obter umInputStream vazio eficiente:

public InputStream getInputStream() {
    return StreamUtils.emptyInput();
}

Existem dois métodos sobrecarregados chamadosnonClosing(). UmInputStream ou umOutputStream pode ser passado como um argumento para esses métodos para obter uma variante deInputStream ouOutputStream que ignora chamadas para o métodoclose():

public InputStream getNonClosingInputStream() throws IOException {
    InputStream in = new FileInputStream("src/test/resources/input.txt");
    return StreamUtils.nonClosing(in);
}

5. Conclusão

Neste tutorial rápido, vimos o que sãoStreamUtils. Também cobrimos todos os métodos da classeStreamUtils e vimos como podemos usá-los.

A implementação completa deste tutorial pode ser encontradaover on GitHub.