I started learning Java from java1.3, and later I mainly used Java 1.4. Later, many new features in Java 1.5 and 1.6 stayed in the "know" status. For example, NiO, although it is said that it can improve performance, but it has not been used and tested in depth, and there are not many work operation files, so there is not much attention. Even if it is used, it is still customary to use Java. io. In this article, although the testing method is very simple and the conclusions are somewhat one-sided, it still shows that NiO performance is opposite to Java During sequential access. io is greatly improved.
Maybe you should update your knowledge. Otherwise, it will be out or already out.
NIO is used for the next file operation or socket writing.
---
From: http://links.techwebnewsletters.com/ctt? KN = 28 & M = 34038811 & R = mzi1mjc3mdazoas2 & B = 0 & J = ntc5njm4mtas1 & mt = 1 & RT = 0
The following is the translation content:
Recently, I have used Java I/O-related functions in my work. Because Java. i/O knows more (after all, it was available earlier), so I started using Java. classes under the I/O package. Later, to test whether NiO can improve file operation performance, I switched to Java. NIO. I was a little shocked by the conclusion I got. Below are some details of the comparison test:
1. In the java. Io test code, I use randomaccessfile to write data directly to the file and search for the insert, read, and delete records in a specific position.
2. Use the filechannel object in the preliminary test code of Java. NiO. NIO is more efficient than Java. Io because NiO is oriented to data chunks, while Java. Io is basically oriented to bytes.
3. To further explore NiO capabilities, I switched to mappedbytebuffer for testing. This class is built on the virtual memory mechanism of the operating system. According to the Java documentation, this class is the best in terms of performance.
For testing, I wrote a small program simulating the employee database. The structure of employee data is as follows:
Class employee {<br/> string last; // The Key <br/> string first; <br/> int ID; <br/> int zip; <br/> Boolean employed; <br/> string comments; <br/>}
The employee data is written into the file and the last name is used as the index key. In the future, you can use this key to load the employee's data from the file. Whether I/O, NiO, or mappedbytebuffers is used, you must first open a randomaccessfile. The following code creates a file named employee. EJB in the user's home directory, sets it to readable and writable, and initializes the corresponding channel and mappedbytebuffer:
String userhome = system. getproperty ("user. home "); <br/> stringbuffer pathname = new stringbuffer (userhome); <br/> pathname. append (file. separator); <br/> pathname. append ("employees. EJB "); <br/> JAVA. io. randomaccessfile journal = <br/> New randomaccessfile (pathname. tostring (), "RW"); </P> <p> // The following sentence is for NiO <br/> JAVA. NIO. channels. filechannel channel = journal. getchannel (); </P> <p> // the following two sentences are used to use mappedbytebuffer <br/> JOURNAL. setlength (page_size); <br/> mappedbytebuffer MBB = <br/> channel. map (filechannel. mapmode. read_write, 0, journal. length ());
After channel. MAP is used for ing, when the file is appended with new data, the previous mappedbytebuffer will not be able to see the data. Because we want to test the read and write operations, when a new record is appended to the file, the mappedbytebuffer needs to be re-mapped to read new data. To improve efficiency and reduce the number of re ing times, when there is not enough space each time, we expand the specific size of the file (for example, 1 K) to prevent re ing for each append new record.
The following is a comparative test of writing employee records:
Code using Java. IO:
Public Boolean addrecord_io (employee EMP) {<br/> try {<br/> byte [] Last = EMP. last. getbytes (); <br/> byte [] First = EMP. first. getbytes (); <br/> byte [] comments = EMP. comments. getbytes (); </P> <p> // just hard-code the sizes for perfomance <br/> int size = 0; <br/> size + = EMP. last. length (); <br/> size + = 4; // strlen-integer <br/> size + = EMP. first. length (); <br/> size + = 4; // strlen-integer <B R/> size + = 4; // EMP. ID-integer <br/> size + = 4; // emp.zip-integer <br/> size + = 1; // EMP. employed-byte <br/> size + = EMP. comments. length (); <br/> size + = 4; // strlen-integer <br/> long offset = getstoragelocation (size ); <br/> // store the record by key and save the offset <br/> // <br/> If (offset =-1) {<br/> // we need to add to the end of the journal. seek there <br/> // Now only if we're not already there <br/> long currentpos = journal. getfilepointer (); <br/> long jounrallen = journal. length (); <br/> If (jounrallen! = Currentpos) <br/> JOURNAL. seek (jounrallen); </P> <p> offset = jounrallen; <br/>} else {<br/> // seek to the returned insertion point <br/> JOURNAL. seek (offset); <br/>}< br/> // fist write the header <br/> JOURNAL. writebyte (1); <br/> JOURNAL. writeint (size); <br/> // next write the data <br/> JOURNAL. writeint (last. length); <br/> JOURNAL. write (last); <br/> JOURNAL. writeint (first. length); <br/> jour Nal. write (first); <br/> JOURNAL. writeint (EMP. ID); <br/> journal.writeint(emp.zip); <br/> If (EMP. employed) <br/> JOURNAL. writebyte (1); <br/> else <br/> JOURNAL. writebyte (0); <br/> JOURNAL. writeint (comments. length); <br/> JOURNAL. write (comments); <br/> // next, see if we need to append an empty record if we inserted <br/> // This new record at an empty location <br/> If (newemptyrecordsize! =-1) {<br/> // simply write a header <br/> JOURNAL. writebyte (0); // inactive record <br/> JOURNAL. writelong (newemptyrecordsize); <br/>}< br/> employeeidx. put (EMP. last, offset); <br/> return true; <br/>}< br/> catch (exception e) {<br/> E. printstacktrace (); <br/>}< br/> return false; <br/>}
Code for using Java. Nio:
Public Boolean addrecord_nio (employee EMP) {<br/> try {<br/> data. clear (); <br/> byte [] Last = EMP. last. getbytes (); <br/> byte [] First = EMP. first. getbytes (); <br/> byte [] comments = EMP. comments. getbytes (); <br/> data. putint (last. length); <br/> data. put (last); <br/> data. putint (first. length); <br/> data. put (first); <br/> data. putint (EMP. ID); <br/> data.putint(emp.zip); <br/> byte employed = 0; <B R/> If (EMP. employed) <br/> employed = 1; <br/> data. put (employed); <br/> data. putint (comments. length); <br/> data. put (comments); <br/> data. flip (); <br/> int datalen = data. limit (); <br/> header. clear (); <br/> header. put (byte) 1); // 1 = active record <br/> header. putint (datalen); <br/> header. flip (); <br/> long headerlen = header. limit (); <br/> int length = (INT) (headerlen + datalen); <br/> lon G offset = getstoragelocation (INT) datalen ); <br/> // store the record by key and save the offset <br/> // <br/> If (offset =-1) {<br/> // we need to add to the end of the journal. seek there <br/> // now only if we're not already there <br/> long currentpos = channel. position (); <br/> long jounrallen = channel. size (); <br/> If (jounrallen! = Currentpos) <br/> channel. position (jounrallen); <br/> offset = jounrallen; <br/>}< br/> else {<br/> // seek to the returned insertion point <br/> channel. position (offset); <br/>}< br/> // fist write the header <br/> long written = channel. write (SRCS); <br/> // next, see if we need to append an empty record if we inserted <br/> // This new record at an empty location <br/> If (newemptyrecords Ize! =-1) {<br/> // simply write a header <br/> data. clear (); <br/> data. put (byte) 0); <br/> data. putint (newemptyrecordsize); <br/> data. flip (); <br/> channel. write (data); <br/>}< br/> employeeidx. put (EMP. last, offset); <br/> return true; <br/>}< br/> catch (exception e) {<br/> E. printstacktrace (); <br/>}< br/> return false; <br/>}
The mappedbytebuffer code is as follows:
Public Boolean addrecord_mbb (employee EMP) {<br/> try {<br/> byte [] Last = EMP. last. getbytes (); <br/> byte [] First = EMP. first. getbytes (); <br/> byte [] comments = EMP. comments. getbytes (); <br/> int datalen = last. length + first. length + comments. length + 12 + 9; <br/> int headerlen = 5; <br/> int length = headerlen + datalen; <br/> // store the record by key and save the offset <br/> // <Br/> long offset = getstoragelocation (datalen); <br/> If (offset =-1) {<br/> // we need to add to the end of the journal. seek there <br/> // now only if we're not already there <br/> long currentpos = MBB. position (); <br/> long journallen = channel. size (); <br/> If (currentpos + length)> = journallen) {<br/> // log ("Growing file by another page "); <br/> MBB. force (); <br/> JOURNAL. setlength (Journallen + page_size); <br/> channel = journal. getchannel (); <br/> journallen = channel. size (); <br/> MBB = channel. map (filechannel. mapmode. read_write, 0, journallen); <br/> currentpos = MBB. position (); <br/>}< br/> If (currentend! = Currentpos) <br/> MBB. position (currentend); <br/> offset = currentend; // journallen; <br/>}< br/> else {<br/> // seek to the returned insertion point <br/> MBB. position (INT) offset); <br/>}< br/> // write header <br/> MBB. put (byte) 1); // 1 = active record <br/> MBB. putint (datalen); <br/> // write data <br/> MBB. putint (last. length); <br/> MBB. put (last); <br/> MBB. putint (first. length); <br/> MBB. Put (first); <br/> MBB. putint (EMP. ID); <br/> mbb.putint(emp.zip); <br/> byte employed = 0; <br/> If (EMP. employed) <br/> employed = 1; <br/> MBB. put (employed); <br/> MBB. putint (comments. length); <br/> MBB. put (comments); <br/> currentend + = length; <br/> // next, see if we need to append an empty record if we inserted <br/> // This new record at an empty location <br/> If (newemptyrecordsize! =-1) {<br/> // simply write a header <br/> MBB. put (byte) 0); <br/> MBB. putint (newemptyrecordsize); <br/> currentend + = 5; <br/>}< br/> employeeidx. put (EMP. last, offset); <br/> return true; <br/>}< br/> catch (exception e) {<br/> E. printstacktrace (); <br/>}< br/> return false; <br/>}
Next, call each method to insert 100,000 records. The time consumption comparison is as follows:
* With Java. IO :~ 10,000 milliseconds
* With Java. Nio :~ 2,000 milliseconds
* With mappedbytebuffer :~ 970 milliseconds
The performance improvement of NiO is very obvious. The performance of mappedbytebuffer is even more surprising.
The performance comparison between the three methods for reading data is as follows:
* With Java. IO :~ 6,900 milliseconds
* With Java. Nio :~ 1,400 milliseconds
* With mappedbytebuffer :~ 355 milliseconds
Similar to writing, NiO significantly improves performance, while mappedbytebuffer is surprisingly efficient. Migrate data from Java. Io to NiO and use mappedbytebuffer, which can be improved by more than 10 times.
For the original test code, visit:
Http://www.ericbruno.com/nio.html