1919import com .google .common .base .Stopwatch ;
2020import com .google .common .io .BaseEncoding ;
2121
22+ import java .io .Closeable ;
2223import java .io .IOException ;
2324import java .net .URI ;
2425import java .nio .ByteBuffer ;
@@ -49,8 +50,16 @@ public class ParallelCountBytes {
4950
5051 /**
5152 * WorkUnit holds a buffer and the instructions for what to put in it.
53+ *
54+ * <p>Use it like this:
55+ * <ol>
56+ * <li> call()
57+ * <li> the data is now in buf, you can access it directly
58+ * <li> if need more, call resetForIndex(...) and go back to the top.
59+ * <li> else, call close()
60+ * </ol>
5261 */
53- private class WorkUnit implements Callable <WorkUnit > {
62+ private static class WorkUnit implements Callable <WorkUnit >, Closeable {
5463 public final ByteBuffer buf ;
5564 final SeekableByteChannel chan ;
5665 final int blockSize ;
@@ -70,7 +79,7 @@ public WorkUnit call() throws IOException {
7079 return this ;
7180 }
7281 chan .position (pos );
73- // read until buffer is full, or EOF
82+ // read until buffer it is full, or EOF
7483 while (chan .read (buf ) > 0 ) {};
7584 return this ;
7685 }
@@ -80,16 +89,16 @@ public WorkUnit resetForIndex(int blockIndex) {
8089 buf .flip ();
8190 return this ;
8291 }
92+
93+ public void close () throws IOException {
94+ chan .close ();
95+ }
8396 }
8497
8598 /**
8699 * See the class documentation.
87100 */
88- public static void main (String [] args ) throws IOException {
89- new ParallelCountBytes ().start (args );
90- }
91-
92- public void start (String [] args ) throws IOException {
101+ public static void main (String [] args ) throws Exception {
93102 if (args .length == 0 || args [0 ].equals ("--help" )) {
94103 help ();
95104 return ;
@@ -100,16 +109,15 @@ public void start(String[] args) throws IOException {
100109 }
101110
102111 /**
103- * Print the length of the indicated file.
112+ * Print the length and MD5 of the indicated file.
104113 *
105114 * <p>This uses the normal Java NIO Api, so it can take advantage of any installed
106115 * NIO Filesystem provider without any extra effort.
107116 */
108- private void countFile (String fname ) throws IOException {
117+ private static void countFile (String fname ) throws Exception {
109118 // large buffers pay off
110119 final int bufSize = 50 * 1024 * 1024 ;
111120 Queue <Future <WorkUnit >> work = new ArrayDeque <>();
112- try {
113121 Path path = Paths .get (new URI (fname ));
114122 long size = Files .size (path );
115123 System .out .println (fname + ": " + size + " bytes." );
@@ -125,14 +133,15 @@ private void countFile(String fname) throws IOException{
125133 for (blockIndex = 0 ; blockIndex < nThreads ; blockIndex ++) {
126134 work .add (exec .submit (new WorkUnit (Files .newByteChannel (path ), bufSize , blockIndex )));
127135 }
128- while (true ) {
136+ while (! work . isEmpty () ) {
129137 WorkUnit full = work .remove ().get ();
130138 md .update (full .buf .array (), 0 , full .buf .position ());
131139 total += full .buf .position ();
132140 if (full .buf .hasRemaining ()) {
133- break ;
141+ full .close ();
142+ } else {
143+ work .add (exec .submit (full .resetForIndex (blockIndex ++)));
134144 }
135- work .add (exec .submit (full .resetForIndex (blockIndex ++)));
136145 }
137146 exec .shutdown ();
138147
@@ -141,12 +150,9 @@ private void countFile(String fname) throws IOException{
141150 String hex = String .valueOf (BaseEncoding .base16 ().encode (md .digest ()));
142151 System .out .println ("The MD5 is: 0x" + hex );
143152 if (total != size ) {
144- System .out .println ("Wait, this doesn't match! We saw " + total + " bytes, " +
145- "yet the file size is listed at " + size + " bytes." );
153+ System .out .println ("Wait, this doesn't match! We saw " + total + " bytes, "
154+ + "yet the file size is listed at " + size + " bytes." );
146155 }
147- } catch (Exception ex ) {
148- System .out .println (fname + ": " + ex .toString ());
149- }
150156 }
151157
152158 private static void help () {
0 commit comments