Ao lado do artigo anterior, continuaremos aprendendo operações de fluxo de bytes em Java.
Decorador Buffer BufferingInput/OutputStream
O fluxo do decorador é na verdade um fluxo de IO de arquivo com base em um padrão de design "Modo Decorator", e nosso fluxo de buffer é apenas um deles. Vamos dar uma olhada.
Antes disso, usamos o arquivo de leitura e gravação FileInputStream e FileOutputStream, leitura e gravação do disco byte ou byte, que consome muito tempo.
Nosso fluxo de buffer pode pré-ler o número de bytes de uma capacidade especificada do disco ao mesmo tempo na memória, e as operações de leitura subsequentes serão lidas diretamente da memória para melhorar a eficiência. Vamos dar uma olhada na implementação específica de fluxos em buffer:
Vamos tomar BufferEnputStream como exemplo primeiro, vamos mencionar brevemente suas propriedades principais:
O BUF é uma matriz de bytes usada para leituras em buffer. Seu valor será preenchido continuamente à medida que o fluxo é lido e as operações de leitura subsequentes podem ser diretamente baseadas nessa matriz em buffer.
Default_buffer_size especifica o tamanho do buffer padrão, ou seja, o comprimento da matriz do BUF. Max_buffer_size especifica o limite superior do buffer.
A contagem aponta para o último índice de bytes válido na matriz em buffer. POS aponta para a próxima posição de índice de bytes a ser lida.
Markpos e Marklimit são usados para repetir operações de leitura.
Em seguida, vamos dar uma olhada em vários exemplos de construtores de bufferInputStream:
public bufferedInputStream (inputStream in) {this (em, default_buffer_size);} public bufferInputStream (InputStream in, int size) {super (in); if (size <= 0) {lança new ilegalArgumentException ("tamanho do buffer <= 0"); } buf = novo byte [size];}No geral, o primeiro precisa passar apenas em uma instância do InputStream que é "decorada" e usar um buffer do tamanho padrão. Este último pode indicar explicitamente o tamanho do buffer.
Além disso, Super (in) salva essa instância do InputStream no campo de atributo no FilterInputStream da classe pai e todas as operações reais de leitura de disco são emitidas por esta instância do InputStream.
Vamos dar uma olhada nas operações de leitura mais importantes e como o buffer está preenchido.
public sincronizado int read () lança ioexception {if (pos> = count) {preench (); if (pos> = count) retornar -1; } return getBufifopen () [pos ++] & 0xff;}Eu acredito que todos já estão familiarizados com esse método. Ele lê o próximo byte do fluxo e o retorna, mas a implementação em detalhes ainda é um pouco diferente.
A contagem aponta para a próxima posição do índice de bytes válido na matriz buffer e POS aponta para a próxima posição do índice de bytes a ser lido. Em teoria, o POS não pode ser maior que a contagem, no máximo igual a.
Se o POS for igual à contagem, significa que todos os bytes válidos na matriz de buffer foram lidos. Neste momento, os dados "inúteis" no buffer precisam ser descartados e um lote de novos dados é recarregado do disco para preencher o buffer.
De fato, o método de preenchimento é o que faz. Ele tem muito código, então não o levarei para analisá -lo. Se você entende sua função, provavelmente é fácil analisar sua implementação.
Se o PDV ainda for igual à contagem após a chamada do método de preenchimento, significa que a instância do InputStream não leu nenhum dado do fluxo, ou seja, não há dados no fluxo de arquivos para ler. Para isso, consulte a linha 246 do método de preenchimento.
Em geral, se o buffer for preenchido com sucesso, nosso método de leitura receberá um byte diretamente do buffer e o devolverá ao chamador.
Public sincronizado int read (byte b [], int off, int len) {// .....}Esse método também é um "conhecido", não tem mais nenhuma explicação desnecessária, a implementação é semelhante.
O método Skip é usado para pular o número de bytes de um comprimento especificado para a leitura contínua do fluxo de arquivos:
public sincronizado Skip longo (longo n) {// ......}Uma coisa a observar é que o método Skip tenta pular N bytes, mas não é garantido que pular n bytes. O método retorna o número real de bytes ignorados. Se o número restante de bytes disponíveis na matriz em buffer for menor que n, o número real de bytes que pode ser ignorado na matriz em buffer será eventualmente ignorada.
Por fim, vamos falar sobre esse método próximo:
public void close () lança IoException {byte [] buffer; while ((buffer = buf)! = null) {if (bufupdater.comparenderndSet (this, buffer, nulo)) {inputStream input = in; in = null; if (input! = null) input.close (); retornar; } // caso contrário, novamente novamente, caso um novo buf BUF tenha sido revestido em preenchimento ()}}O método de fechamento esvaziará o fluxo "decorado" e chamará seu método de fechamento para liberar recursos relevantes, que eventualmente limparão o espaço de memória ocupado pela matriz de buffer.
O bufferInputStream fornece recursos de buffer de leitura, enquanto o BufferoudOutputStream fornece recursos de buffer de gravação, ou seja, as operações de gravação de memória não serão atualizadas imediatamente para o disco e serão salvas temporariamente no buffer e serão escritas juntas quando o buffer estiver cheio.
byte protegido buf []; Count INT protegido;
BUF representa o buffer interno e a contagem representa a capacidade de dados real no buffer, ou seja, o número de bytes eficazes no BUF, em vez do comprimento da matriz BUF.
public bufferoudOutputStream (outputStream out) {this (out, 8192);} public buffaredOutputStream (outputStream Out, int size) {super (out); if (size <= 0) {lança new ilegalArgumentException ("tamanho do buffer <= 0"); } buf = novo byte [size];}Com a mesma ideia de implementação, é necessário fornecer uma instância de fluxo de saída de saída de saída e o tamanho do buffer também pode ser opcionalmente especificado.
public sincronizado void write (int b) lança IoException {if (count> = buf.length) {flushBuffer (); } buf [count ++] = (byte) b;}O método de gravação verificará primeiro se o buffer ainda pode acomodar esta operação de gravação. Se uma operação de gravação em disco não puder ser iniciada, todos os dados do buffer serão gravados no arquivo de disco, caso contrário, o buffer será gravado no buffer primeiro.
Obviamente, o BufferedOutputStream também fornece um método de descarga para fornecer uma interface para o exterior, ou seja, você não precisa esperar até que o buffer esteja cheio antes de escrever dados no disco. Você também pode chamar explicitamente esse método para limpar o buffer e atualizar os arquivos de disco.
public sincronizado void Flush () lança IoException {FlushBuffer (); out.flush ();}Em relação aos fluxos em buffer, o conteúdo principal é introduzido como acima. Este é um fluxo que pode melhorar significativamente a eficiência. Por meio dele, o número de acessos em disco pode ser reduzido e a eficiência da execução do programa pode ser aprimorada.
Não discutiremos o fluxo de serialização do objeto ObjectInput/OutputStream e o Decorator Stream Datainput/OutputStream com base nos tipos básicos. Quando aprendermos a serialização, discutiremos esses dois fluxos de bytes novamente.
Todos os códigos, imagens e arquivos no artigo são armazenados na nuvem no meu github:
(https://github.com/singleyam/overview_java)
Você também pode optar por baixar localmente.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.