Análise de princípios
Durante o desenvolvimento, a função de "transmissão contínua do ponto de interrupção" é muito prática e comum, e também parece mais "padrão". Portanto, geralmente estamos interessados em estudar como essa função é implementada?
Em Java, você também pode encontrar muitas informações sobre a implementação de funções semelhantes na Internet. No entanto, a maioria deles dá uma demonstração e publica o código -fonte. Existem muito poucas explicações detalhadas para seu princípio de implementação.
Então, quando entramos em contato com ele, podemos usar diretamente os códigos CRTL + C/V e depois mexer com ele, mas podemos finalmente obter o efeito. Mas fazer isso quando você é iniciante é obviamente bom e ruim.
A vantagem é que existem muitos códigos de origem e poucas explicações; Se estivermos dispostos a trabalhar duro, procuraremos informações e estudaremos as coisas que não entendemos no código publicado por outras pessoas. No final, você provavelmente receberá muitas recompensas.
As desvantagens também são óbvias: como iniciante, ao enfrentar muito código -fonte, parece que muitas coisas não são familiares, por isso é fácil ser assustado. Mesmo se você tiver um entendimento aproximado do uso no final, pode não necessariamente entender o princípio da implementação.
Hoje, vamos começar da perspectiva mais básica e ver se a chamada "continuação do ponto de interrupção" é realmente tão "sofisticada".
De fato, quando você entra em contato com uma nova "coisa", pode transformá -la em algo com o qual estamos mais familiarizados para nos referir e comparar e aprender. Geralmente será o dobro do resultado com metade do esforço.
Se estivermos expostos ao conceito de "transmissão contínua do ponto de interrupção", será definitivamente difícil explicar claramente um, dois e três. Então, definitivamente estaremos familiarizados com "Jogando".
OK, então vamos supor que agora temos um "jogo de RPG de nível claro". Pense no que geralmente fazemos ao jogar esse tipo de jogo?
É óbvio que, no primeiro dia, travamos batalhas sangrentas e matamos todos, assumindo que finalmente chegamos ao quarto nível. Embora a feroz batalha estivesse em pleno andamento, quando olhei para o relógio na parede, já eram 12 da manhã e era hora de ir para a cama.
Foi muito embaraçoso neste momento. Para acompanhar com sucesso o progresso do nosso jogo na próxima vez que jogarmos, o que devemos fazer?
É muito simples. Não desligamos o jogo, vamos para a cama e continuamos jogando no dia seguinte. Tudo bem, mas parece que há algo que faz as pessoas se sentirem desconfortáveis.
Portanto, neste momento, se o jogo tiver uma função chamada "Salvar", será muito importante. Selecionamos diretamente o arquivo, entramos no nome do arquivo "Quarto nível" e depois podemos fechar o jogo.
Quando jogamos o jogo da próxima vez, encontraremos diretamente o "quarto nível", depois leremos o arquivo e, em seguida, podemos continuar jogando o jogo.
Neste momento, é fácil entender a chamada "ponto de interrupção" de transmissão contínua ". Vamos seguir nossa ideia anterior de "jogar":
Suponha que exista um arquivo que precisamos baixar agora. Quando baixamos parte dele, ocorre uma situação, como: o computador trava, a energia está fora, a rede é interrompida, etc.
Na verdade, é como quando estávamos jogando antes, de repente precisávamos ir para a cama e descansar às 12 horas. OK, então a situação neste momento é:
• Se o jogo não puder ser salvo, significa que, da próxima vez que jogarmos, o progresso dos 4 níveis que passaram desta vez será perdido e não podemos seguir o jogo.
• Correspondentemente, se o comportamento de "download" não puder gravar um progresso desse download. Então, quando baixamos esse arquivo novamente, só podemos começar de novo.
Nesse ponto, descobrimos que a chave do comportamento que mencionamos acima é a palavra " continue "!
Para alcançar o objetivo de "continuar" um comportamento desconectado, a chave é ter uma "mídia" capaz de gravar e ler as informações do nó em que o comportamento tem uma "interrupção".
Transforme no mundo da programação
De fato, este é o princípio mais básico de "transmissão contínua do ponto de interrupção". Em palavras claras, precisamos gravar as informações de localização de interrupção quando o comportamento do download é interrompido e depois lê -las no próximo comportamento.
Com essas informações de localização, pense no que devemos fazer. Sim, é muito simples. Quando um novo comportamento de download começar, faça o download do conteúdo diretamente deste local do registro e não começa mais do zero.
Bem, conversamos sobre o princípio de tanto tempo em linguagem simples e começamos a se sentir entediados. Então, vamos resumir no final e depois dar uma olhada em como devemos converter os princípios no mundo da programação.
• Quando o "comportamento de upload (download)" é interrompido, precisamos gravar o local (posição) deste upload (download).
• Quando o comportamento "continuar" começa, pulamos diretamente para a postagem para continuar fazendo o upload (download).
Obviamente, a chave do problema está na chamada "posição". No "jogo de nível de passagem" que mencionamos, "que nível" pode ser usado como a unidade desta posição.
Então, quando mudamos para a chamada "Transmissão contínua do ponto de interrupção", o que devemos usar para medir a "posição"? Obviamente, está de volta ao binário, porque a essência aqui nada mais é do que ler e escrever arquivos.
Então o resto do trabalho é muito simples. Primeiro, registre a posição, que parece não ser nada que valha a pena falar, porque é apenas a persistência de dados (memória, arquivos, banco de dados) e temos muitas maneiras.
Outra chave é que, quando o comportamento "contínuo" começa, precisamos iniciar as operações de leitura e gravação da posição de posição que gravamos da última vez, para que precisemos de algo semelhante à função "ponteiro".
Obviamente, também podemos encontrar uma maneira de implementar esse "ponteiro", mas feliz que o Java nos tenha fornecido uma classe dessa classe, ou seja, RandomAccessFile.
A função desta classe é refletida intuitivamente em seu nome e pode acessar arquivos aleatoriamente. Vamos dar uma olhada na descrição desta classe na documentação da API:
Instâncias desta classe Suporte a leitura e gravação em arquivos acessados aleatoriamente. O acesso aleatório aos arquivos se comporta como uma grande matriz de bytes armazenada no sistema de arquivos.
Se um arquivo for acessado aleatoriamente no modo de leitura/gravação, a operação de saída também estará disponível; A operação de saída começa com o ponteiro do arquivo e avança o ponteiro do arquivo à medida que o byte é gravado.
Uma operação de saída depois de escrever no final atual de uma matriz implícita faz com que a matriz se expanda. O ponteiro do arquivo pode ser lido através do método getFilePointer e definido através do método Seek.
Depois de ler as instruções da API, rimos. Sim, não é exatamente isso que queremos? Bem, estamos afiando nossa faca há tanto tempo, por que não cortamos madeira?
Exemplo de demonstração
Como é para a "continuação do ponto de interrupção" dos arquivos, é óbvio que primeiro criaremos um arquivo. Talvez arquivos de áudio, arquivos de imagem etc. pareçam um pouco mais elegantes.
Mas já dissemos que, aos olhos dos grandes irmãos de computador, eles acabarão retornando ao "binário". Portanto, criaremos um arquivo "txt" simples aqui, porque o TXT é mais propício ao entendimento.
Criamos um arquivo chamado "test.txt" no diretório raiz do disco D. O conteúdo do arquivo é muito simples, como mostrado na figura:
É isso mesmo, o que digitamos são 6 letras inglesas simples. Em seguida, clique com o botão direito do mouse → Propriedades:
Vemos que o arquivo agora tem 6 bytes de tamanho. É por isso que dizemos que tudo é inseparável de "binário".
Sim, todos nós entendemos porque inserimos 6 letras em inglês e o espaço de armazenamento que 1 carta em inglês ocupará é 1 byte (ou seja, 8 bits).
Até agora, o que vimos é chato, porque isso é basicamente absurdo, e as pessoas com um pouco de conhecimento de computador conhecem esse conhecimento. Não se preocupe, vamos continuar.
É fácil ler e escrever um arquivo em Java. Suponha que o requisito atual seja "Escreva este arquivo da unidade d para a unidade e", então elevaremos o teclado e faremos com que ele faça!
Mas o chamado "Upload (Download)" não é o chamado arquivo? A única diferença é que o comportamento muda de "apenas entre nativos" para "entre nativos" para "entre nativos", leitura e escrita de arquivos.
Neste momento, diremos: "Pare de insistir, todo mundo sabe essas coisas, e a 'transmissão contínua do ponto de interrupção'?" De fato, já é muito simples aqui. Vamos deixar claro novamente que o que precisamos fazer na transmissão contínua do ponto de interrupção é:
Se houver uma interrupção no comportamento anterior de leitura e gravação, grave as informações de localização do conteúdo do arquivo que foram lidas e escreva desta vez; Quando "continuação inicia", mova diretamente o ponteiro aqui e comece a continuar a operação de leitura e gravação.
A ênfase repetida no princípio é realmente porque, enquanto o princípio for entendido, o restante é apenas movimentos. É como o dharma "Nove nove retornam a um" em romances de artes marciais, o mais alto nível é retornar à fonte original.
Enquanto entendermos o princípio de qualquer coisa complexa, podemos retirá -lo e reduzi -lo a coisas simples. Da mesma forma, uma série de coisas simples, através da combinação lógica, formam coisas complexas.
Em seguida, voltaremos ao caos em breve e simularemos uma "transmissão contínua do ponto de interrupção" na forma mais básica. Aqui nem escrevemos o código do servidor e apenas fazemos isso através de uma classe de teste local.
O efeito que queremos alcançar é muito simples: escreva o arquivo "test.txt" no disco d no disco e, mas simularemos o comportamento "interromper" no meio do processo e continuaremos a fazer o upload novamente para finalmente concluir todo o processo.
Em outras palavras, consideraremos "d drive" como um computador aqui e consideraremos diretamente "e unidade" como um servidor. Em seguida, não teremos mais a ver com o protocolo HTTP por meio centavo (é claro, ainda devemos ter a ver com isso no desenvolvimento real), por isso nos preocupamos apenas com os princípios mais básicos de "quebrar" e "continuar" para ler e escrever arquivos.
Para aprofundar nossa compreensão por meio da comparação, primeiro escrevemos uma parte normal de código, ou seja, leia e escrevemos normalmente sem interrupção:
public class Test {public static void main (string [] args) {// FILOS ORIGE e TARGEN FILE ORONTFILE = NOVO FILE ("D:/", "test.txt"); Arquivo TargetFile = novo arquivo ("e:/", "test.txt"); // fluxo de entrada e saída FileInputStream fis = null; FileOutputStream fos = null; // buffer de dados byte [] buf = novo byte [1]; tente {fis = new FileInputStream (Sourcefile); fos = new FileOutputStream (TargetFile); // Leia e escreva dados while (fis.read (buf)! = -1) {System.out.println ("Escreva dados ..."); fos.write (buf); }} catch (filenotfoundException e) {System.out.println ("O arquivo especificado não existe"); } catch (ioexception e) {// TODO: lide a exceção} finalmente {tente {// feche o fluxo de entrada e saída se (fis! = null) fis.close (); if (fos! = null) fos.close (); } catch (ioexception e) {e.printStackTrace (); }}}} Quando este código for executado, descobriremos que uma cópia de "test.txt" foi copiada com sucesso no disco E. Este código é muito simples, a única coisa a dizer é:
Vemos que definimos o BUF, ou seja, o tamanho do buffer é 1, o que realmente significa que cada vez que lemos, lemos um byte de dados (ou seja, 1 carta em inglês).
Agora, vamos simular o comportamento das interrupções de leitura e gravação. Apertaremos o código anterior da seguinte maneira:
importar java.io.file; importar java.io.fileInputStream; importar java.io.filenotfoundException; importar java.io.fileOutputStream; importar java.io.ioexception; importar java.io.randomaccessfile; teste público {private static int = -1; public static void main (string [] args) {// Origem e arquivos de destino FILE ORONTFILE = novo arquivo ("d:/", "test.txt"); Arquivo TargetFile = novo arquivo ("e:/", "test.txt"); // fluxo de entrada e saída FileInputStream fis = null; FileOutputStream fos = null; // buffer de dados byte [] buf = novo byte [1]; tente {fis = new FileInputStream (Sourcefile); fos = new FileOutputStream (TargetFile); // Dados Leia e escreva while (fis.read (buf)! = -1) {fos.write (buf); // Quando 3 bytes de conteúdo de arquivo foram enviados, a rede interrompe e uma exceção são lançados se (TargetFile.Length () == 3) {Position = 3; lançar novo FileAcSesception (); }}} Catch (FileAcSesception E) {KeepTer (SourceFile, TargetFile, Position); } catch (filenotfoundException e) {System.out.println ("especificar o arquivo não existe"); } catch (ioexception e) {// TODO: lide a exceção} finalmente {tente {// feche o fluxo de entrada e saída se (fis! = null) fis.close (); if (fos! = null) fos.close (); } catch (ioexception e) {e.printStackTrace (); }}} Void estático privado KeepTer (fonte do arquivo, destino do arquivo, int position) {try {thread.sleep (10000); } catch (interruptedException e) {// TODO BLOCO DE CATCH AUTOGERATIDO E.PRINTSTACKTRACE (); } tente {RandomAccessFile ReadFile = new RandomAccessFile (fonte, "RW"); RandomAccessFile writefile = new RandomAccessFile (Target, "RW"); readfile.seek (posição); writefile.seek (posição); // buffer de dados byte [] buf = novo byte [1]; // Dados Leia e escreva while (readfile.read (buf)! = -1) {writefile.write (buf); }} catch (filenotfoundException e) {// TODO GATE GENERADO AUTOMENTADO BLOCO E.PRINTSTACKTRACE (); } catch (ioexception e) {// TODO GATO GENERADO AUTOMENTADO BLOCO E.PRINTSTACKTRACE (); }}} classe FileAcceSception estende a exceção {}Para resumir, que trabalho fizemos nessa mudança:
• Primeiro, definimos uma posição variável para registrar o local em que a leitura e a gravação foi concluída quando ocorre uma interrupção. (Isso é por conveniência. De fato, deve -se dizer que esse valor deve ser armazenado em um arquivo ou banco de dados para persistência)
• Então, no loop while de leitura e escrita de arquivos, simulamos a ocorrência de um comportamento de interrupção. Aqui, quando o comprimento do arquivo do arquivo de destino é de 3 bytes, ele simula lançando uma exceção que personalizamos. (Podemos imaginar que, no download real, o conteúdo de "X" bytes foi enviado (baixado) e a rede é interrompida neste momento, então gravaremos "X" na exceção lançada pela interrupção da rede).
• O resto é como disse antes, depois que o comportamento da "continuação" começa, envolvemos nosso arquivo na classe RandomAccessFile e depois especificamos o ponteiro para o local em que a interrupção anterior ocorreu para leitura e escrita através de busca.
(Para download e upload de arquivos reais, é claro que precisamos fazer o upload do valor de interrupção salvo para o servidor. Esse método geralmente é httpconnection.setRequestProperty ("range", "bytes = x"););)
Em nosso código, ative o comportamento "contínuo", ou seja, o método de mantimento: começamos a deixar o thread dormir por 10 segundos, o que é precisamente para nos deixar executar o programa e ver o efeito.
Agora que executamos o programa, o arquivo iniciará o "processo de upload do disco D para o disco E". Primeiro, clicamos no disco E e descobrimos que existe realmente um arquivo de teste.txt adicional. Abra -o e encontre o conteúdo da seguinte forma:
É isso mesmo, neste momento descobrimos que o conteúdo só tem "ABC". Isso está dentro de nossas expectativas, porque nossa simulação de programa interrompe quando o arquivo é carregado por 3 bytes.
Ok, vamos esperar em silêncio por 10 segundos para passar e, em seguida, clique no arquivo para ver se ele pode ter sucesso:
Através das capturas de tela, descobrimos que o conteúdo se tornou "ABC" e, portanto, a continuação foi concluída.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.