Principle analysis
During development, the function of "breakpoint continuous transmission" is very practical and common, and it also sounds more "standard". So we are usually interested in studying how this function is implemented?
In Java, you can also find a lot of information on implementing similar functions on the Internet. However, most of them give a demo and post the source code. There are very few detailed explanations for its implementation principle.
So when we first came into contact with it, we might just directly use Crtl + C/V codes and then tinker with it, but we can finally get the effect out. But doing this when you are beginners is obviously good and bad.
The advantage is that there are many source codes and few explanations; if we are willing to work hard, we will search for information and study the things we don’t understand in the code posted by others. In the end, you will probably get a lot of rewards.
The disadvantages are also obvious: as a beginner, when facing a lot of source code, it feels like a lot of things are unfamiliar, so it is easy to be daunted. Even if you have a rough understanding of the usage in the end, you may not necessarily understand the implementation principle.
Today, let’s start from the most basic perspective and see if the so-called “breakpoint continuation” is really so “high-end”.
In fact, when you come into contact with a new "thing", you can transform it into something that we are more familiar with to refer to and compare and learn. Usually it will be twice the result with half the effort.
If we are just exposed to the concept of "breakpoint continuous transmission", it will definitely be difficult to explain clearly one, two, and three. Then, we will definitely be familiar with "playing games".
OK, then let's assume we now have a "clear-level RPG game". Think about what we usually do when playing this kind of game?
It is obvious that on the first day we fought bloody battles and killed everyone, assuming that we finally arrived at the fourth level. Although the fierce battle was in full swing, when I looked at the clock on the wall, it was already 12 a.m. and it was time to go to bed.
It was very embarrassing at this time. In order to successfully keep pace with the progress of our game next time we play, what should we do?
It's very simple. We don't turn off the game, we go to bed, and continue playing the next day. This is OK, but it seems that there is something that makes people feel uncomfortable.
So, at this time, if the game has a function called "Save", it will be very important. We directly select the archive, enter the archive name "Fourth Level", and then we can close the game.
When we play the game next time, we will directly find the "Fourth Level" save, then read the file, and then we can continue to play the game.
At this time, the so-called "breakpoint continuation" is easy to understand. Let’s follow our previous idea of “playing games”:
Suppose that there is a file that we need to download now. When we download part of it, a situation occurs, such as: the computer crashes, the power is out, the network is interrupted, etc.
In fact, this is like when we were playing games before, we suddenly needed to go to bed and rest at 12 o'clock. OK, then the situation at this time is:
• If the game cannot be saved, it means that the next time we play, the progress of the 4 levels that have passed this time will be lost and we cannot follow the game.
• Correspondingly, if the "download" behavior cannot record a progress of this download. Then, when we download this file again, we can only start over.
At this point, we have actually discovered that the key to the behavior we mentioned above is the word " continue "!
To achieve the purpose of "continuing" a disconnected behavior, the key is to have a "media" able to record and read the information of the node where the behavior has an "interruption".
Transform to the programming world
In fact, this is the most basic principle of "breakpoint continuous transmission". In plain words, we need to record the interrupt location information when the download behavior is interrupted, and then read it in the next behavior.
With this location information, think about what we should do. Yes, it's very simple. When a new download behavior begins, download content directly from this location of the record, and no longer starts from scratch.
Well, we have been talking about the principle of so long in plain language and started to feel bored. So let’s summarize it at the end and then take a look at how we should convert the principles into the programming world.
• When the "upload (download) behavior" is interrupted, we need to record the location (position) of this upload (download).
• When the "continue" behavior begins, we jump directly to the post to continue uploading (downloading).
Obviously, the key to the problem lies in the so-called "position". In the "passing level game" we mentioned, "what level" can be used as the unit of this position.
So when we switch to the so-called "breakpoint continuous transmission", what should we use to measure "position"? Obviously, it is back to binary because the essence here is nothing more than reading and writing files.
Then the rest of the work is very simple. First, record the position, which seems to be nothing worth talking about, because it is just the persistence of data (memory, files, database), and we have many ways.
Another key is that when the "continued" behavior starts, we need to start the read and write operations from the position position we recorded last time, so we need something similar to the "pointer" function.
Of course, we can also find a way to implement such a "pointer", but happy that Java has provided us with such a class, that is, RandomAccessFile.
The function of this class is intuitively reflected in its name, and it can access files randomly. Let's take a look at the description of this class in the API documentation:
Instances of this class support read and write to randomly accessed files. Random access to files behaves like a large byte array stored in the file system.
If a file is randomly accessed in read/write mode, the output operation is also available; the output operation starts with the file pointer and advances the file pointer as the byte is written.
An output operation after writing to the current end of an implicit array causes the array to expand. The file pointer can be read through the getFilePointer method and set through the seek method.
After reading the API instructions, we laughed. Yes, isn’t this exactly what we want? Well, we have been sharpening our knife for so long, why don’t we chop wood?
Example Demonstration
Since it is for the "breakpoint continuation" of files, it is obvious that we will first create a file. Maybe audio files, image files, etc. will look a little more classy.
But we have already said that in the eyes of the big computer brothers, they will eventually return to "binary". So we will create a simple "txt" file here, because txt is more conducive to understanding.
We create a file named "test.txt" in the root directory of disk D. The file content is very simple, as shown in the figure:
That's right, what we typed is 6 simple English letters. Then we right-click → Properties:
We see that the file is now 6 bytes in size. This is why we say that everything is inseparable from "binary".
Yes, we all understand because we entered 6 English letters, and the storage space that 1 English letter will occupy is 1 byte (i.e. 8 bits).
So far, what we've seen is boring, because this is basically nonsense, and people with a little bit of computer knowledge know this knowledge. Don't worry, let's continue.
It is easy to read and write a file in Java. Suppose the current requirement is "write this file from drive D to drive E", then we will lift the keyboard and get it done!
But isn’t the so-called “upload (download)” of the so-called file? The only difference is that the behavior changes from "just between natives" to "between natives" to "between natives" file reading and writing.
At this time, we will say, "Stop urging, everyone knows these things, what about 'breakpoint continuous transmission'?" In fact, it is already very simple here. We will make it clear again that what we need to do in breakpoint continuous transmission is:
If there is an interruption in the previous read and write behavior, please record the location information of the file contents that have been read and write this time; when "Continuation Starts", directly move the pointer here and start continuing the read and write operation.
The repeated emphasis on the principle is actually because as long as the principle is understood, the rest is just moves. This is just like the "Nine Nine Return to One" Dharma in martial arts novels, the highest level is to return to the original source.
As long as we understand the principle of any complex thing, we can strip it away and reduce it to simple things. Similarly, a series of simple things, through logical combination, form complex things.
Next, we will return to chaos soon and simulate a "breakpoint continuous transmission" in the most basic form. Here we don’t even write the server code, and we just do it through a local test class.
The effect we want to achieve is very simple: write the "test.txt" file on disk D to disk E, but we will simulate the "interrupt" behavior in the middle of the process, and then continue to upload again to finally complete the entire process.
In other words, we will regard "D drive" as a computer here, and directly regard "E drive" as a server. Then we will no longer have to do with the http protocol for half a cent (of course, we must still have to do with it in actual development), so we only care about the most basic principles of "breaking" and "continuing" for reading and writing files.
In order to deepen our understanding through comparison, we first write a normal piece of code, that is, read and write normally without interruption:
public class Test { public static void main(String[] args) { // Source and target files File sourceFile = new File("D:/", "test.txt"); File targetFile = new File("E:/", "test.txt"); // Input and output stream FileInputStream fis = null; FileOutputStream fos = null; // Data buffer byte[] buf = new byte[1]; try { fis = new FileInputStream(sourceFile); fos = new FileOutputStream(targetFile); // Read and write data while (fis.read(buf) != -1) { System.out.println("write data..."); fos.write(buf); } } catch (FileNotFoundException e) { System.out.println("Specified file does not exist"); } catch (IOException e) { // TODO: handle exception } finally { try { // Close the input and output stream if (fis != null) fis.close(); if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } } }} When this code is run, we will find that a copy of "test.txt" has been successfully copied in disk E. This code is very simple, the only thing to say is:
We see that we set the buf, that is, the size of the buffer is 1, which actually means that each time we read, we read a byte of data (i.e. 1 English letter).
Now, let’s simulate the behavior of read and write interrupts. We will perfect the previous code as follows:
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.RandomAccessFile;public class Test { private static int position = -1; public static void main(String[] args) { // Source and target files File sourceFile = new File("D:/", "test.txt"); File targetFile = new File("E:/", "test.txt"); // Input and output stream FileInputStream fis = null; FileOutputStream fos = null; // Data buffer byte[] buf = new byte[1]; try { fis = new FileInputStream(sourceFile); fos = new FileOutputStream(targetFile); // Data read and write while (fis.read(buf) != -1) { fos.write(buf); // When 3 bytes of file content have been uploaded, the network interrupts and an exception is thrown if (targetFile.length() == 3) { position = 3; throw new FileAccessException(); } } } catch (FileAccessException e) { keepGoing(sourceFile,targetFile, position); } catch (FileNotFoundException e) { System.out.println("Specify file does not exist"); } catch (IOException e) { // TODO: handle exception } finally { try { // Close the input and output stream if (fis != null) fis.close(); if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } } } private static void keepGoing(File source,File target, int position) { try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { RandomAccessFile readFile = new RandomAccessFile(source, "rw"); RandomAccessFile writeFile = new RandomAccessFile(target, "rw"); readFile.seek(position); writeFile.seek(position); // Data buffer byte[] buf = new byte[1]; // Data read and write while (readFile.read(buf) != -1) { writeFile.write(buf); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class FileAccessException extends Exception {}To sum up, what work we did in this change:
• First, we define a variable position to record the location where read and write has been completed when an interrupt occurs. (This is for convenience. In fact, it should be said that this value should be stored in a file or database for persistence)
• Then in the while loop of file reading and writing, we simulate the occurrence of an interrupt behavior. Here, when the file length of the targetFile is 3 bytes, it simulates throwing an exception we customized. (We can imagine that in the actual download, the content of "x" bytes has been uploaded (downloaded) and the network is interrupted at this time, so we will record "x" in the exception thrown by the network interrupt).
• The rest is as we said before, after the "continuation" behavior begins, we wrap our file through the RandomAccessFile class, and then specify the pointer to the location where the previous interrupt occurred for reading and writing through seek.
(For actual file download and upload, of course we need to upload the saved interrupt value to the server. This method is usually httpConnection.setRequestProperty("RANGE","bytes=x");)
In our code, enable the "continued" behavior, that is, the keepGoing method: we start to let the thread sleep for 10 seconds, which is precisely to let us run the program and see the effect.
Now that we run the program, the file will start the "process of uploading from D disk to E disk". First, we click on the E disk and find that there is indeed an additional test.txt file. Open it and find the content as follows:
That's right, at this time we found that the content only has "abc". This is within our expectations, because our program simulation interrupts when the file is uploaded by 3 bytes.
Ok, let's wait quietly for 10 seconds to pass, and then click on the file to see if it can succeed:
Through screenshots, we found that the content has indeed become "abc", and thus the continuation was completed.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.