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.