Java 利用Linux Openssl 库计算文件校验码

在传统Java编程中, 我们可以另用ProcessBuilder类来创建系统进程或者Runtime类来取得JVM的接口对象运行我们指定的系统命令, 并且可以通过读入器来获取系统的out以及err输出.这里有一个简单的例子, 没有用过的同学可以参考一下. 

http://wuhongyu.iteye.com/blog/461477 

由于前段时间有这样的一个需求, 尽可能快的算出Hadoop系统里的MD码, 我曾经想过另用Java的Digest类来读取文件, 然后工作交给Digest类来完成, 可没想到的是Java的这个类算MD校验码,效率及其的低下,我在XP上算50M的文件, 居然花费8秒钟的时间.直接放弃. 这个Demo我也顺便推荐一下: 

http://www.javablogging.com/?s=Java+Digest+SHA1+MD5 

后来google该问题的解决方案, 有一个比较有意思的贴子Fast MD5 Implementation in Java, 呵呵, 由于时间关系, 没来的急看,分享一下: 

http://www.twmacinta.com/myjava/fast_md5.php 

Fast MD5.. 总给我一个不太舒服的感觉, 最后还是决定放弃使用. 由于Hadoop运行于Linux 环境, 回过神来我想到了Linux上的openssl库. 大伙都知道openssl 里其中就有计算数据的安全通信命令. $cat XXX | openssl sha1. 

这里有一个问题, 由于hadoop的文件是存在于集群的, 而openssl 是接受本地文件作为参数的, 我可以把文件从HDFS里读出, 然后再构造文件供openssl 计算. 不过这种方式太囧. 
我的解决方法是另用Runtime获取运行对象, 直接执行openssl sha1命令, 其实当系统执行该命令的时候会等待输入的. 此时我可以通过我的文件输入流把数据打印到等待输入的输出流上。 

Java代码   收藏代码
  1. // TODO this is a job. not a filedescriptor  
  2.     protected void handle(FileDescriptor job) throws IOException {  
  3.         if (job == null || job.path == null) {  
  4.             log.warn("Invalid job: " + job);  
  5.         }  
  6.           
  7.         // wait for GC.   
  8.         Configuration conf = new Configuration();  
  9.         Path path = new Path(job.path);  
  10.         FileSystem fs = path.getFileSystem(conf);  
  11.           
  12.         if (!fs.exists(path) || !fs.isFile(path)) {  
  13.             log.warn("*HADLEJOB file does not exist for path: " + path);  
  14.             return;  
  15.         }  
  16.           
  17.         InputStream is = fs.open(path);  
  18.         // Run a command  
  19.         String cmd = "openssl sha1";  
  20.         boolean completed = false;  
  21.           
  22.         Process process = null// Sub process used to execute the command  
  23.         int exitCode;  
  24.         process = Runtime.getRuntime().exec(cmd);  
  25.   
  26.         BufferedOutputStream os = new BufferedOutputStream(process.getOutputStream(), 4096);  
  27.         byte buf[] = new byte[4096];  
  28.         while (true) {  
  29.             int bytesRead = is.read(buf);  
  30.             if (bytesRead == -1) {  
  31.                 break;  
  32.             }  
  33.             os.write(buf, 0, bytesRead);  
  34.         }  
  35.         os.flush();  
  36.         os.close();  
  37.           
  38.         final BufferedReader errReader =   
  39.             new BufferedReader(new InputStreamReader(process.getErrorStream()));  
  40.           
  41.         BufferedReader inReader =   
  42.             new BufferedReader(new InputStreamReader(process.getInputStream()));  
  43.           
  44.         final StringBuffer errMsg = new StringBuffer();  
  45.         // read error and input streams as this would free up the buffers  
  46.         // free the error stream buffer  
  47.         Thread errThread = new Thread(){  
  48.               
  49.             public void run() {  
  50.                 try {  
  51.                     String line = errReader.readLine();  
  52.                     while ((line != null) && !isInterrupted()) {  
  53.                         errMsg.append(line);  
  54.                         errMsg.append(System.getProperty("line.separator"));  
  55.                         line = errReader.readLine();  
  56.                     }  
  57.                 } catch (IOException ioe) {  
  58.                     log.warn("Error reading the error stream", ioe);  
  59.                 }  
  60.             }  
  61.               
  62.         };  
  63.         try {  
  64.             errThread.start();  
  65.         } catch (IllegalStateException ise) {  
  66.         }  
  67.           
  68.         try {  
  69.             String line = inReader.readLine();  
  70.             if (line == null) {  
  71.                 throw new IOException("Exception a line not the end of stream");  
  72.             }  
  73.             job.set_sha1(line.trim());  
  74.             // clear the input stream buffer  
  75.             line = inReader.readLine();  
  76.             while (line != null) {  
  77.                 line = inReader.readLine();  
  78.             }  
  79.               
  80.             // wait for the process to finish and check the exit code  
  81.             exitCode = process.waitFor();  
  82.               
  83.             try {  
  84.                 errThread.join();  
  85.             } catch (InterruptedException ie) {  
  86.                 log.warn("Interrupted while reading the error stream", ie);  
  87.             }  
  88.             completed = true;  
  89.             if (exitCode != 0) {  
  90.                 throw new IOException(exitCode + errMsg.toString());  
  91.             }  
  92.         } catch (InterruptedException ie) {  
  93.             throw new IOException(ie.toString());  
  94.         } finally {  
  95.             // close the input stream  
  96.             try {  
  97.                 inReader.close();  
  98.             } catch (IOException e) {  
  99.                 log.warn("Error whilke closing the input stream", e);  
  100.             }  
  101.             if (!completed) {  
  102.                 errThread.interrupt();  
  103.             }  
  104.             try {  
  105.                 errReader.close();  
  106.             }catch(IOException ioe){  
  107.                 log.warn("Error while closing the error stream", ioe);  
  108.             }  
  109.             process.destroy();  
  110.         }  
  111.     }  


该执行方法运行于线程池中, 下一个贴子我将记录真正应用中线程池的实现, 提供线程池的大小设置, shrink等实现. 

你可能感兴趣的:(java,linux,hadoop,Google,null,Path)