2015-07-21 50 views
1

略微怪異的一系列問題,但我使用的時候運行到建立在Windows 7上我做得有點怪異使用mklink一個符號鏈接,由於存在260個字符的限制問題cmd.exe通過使用Process創建我的Java源代碼中的符號鏈接。因爲我不能完全解釋,下面的代碼:JVM運行時在Windows上創建一個符號鏈接

import java.io.BufferedInputStream; 
import java.io.BufferedReader; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 
import java.util.Arrays; 

public class WindowsSymlinkUtility { 

    private List<String> command, currentSymlinks; 

    public WindowsSymlinkUtility() { 
     this.command = this.currentSymlinks = new ArrayList<String>(); 
     this.command.add("cmd.exe"); 
     this.command.add("/C"); 
    } 

    /** 
    * Automatically creates a directory junction 
    * @param String link - the path and name of the symlink 
    * @param String target - the directory to point the symlink to 
    * @return boolean 
    * @see http://ss64.com/nt/mklink.html 
    */ 
    public boolean createSymlink(String link, String target) { 
     return createSymlink("\\J", link, target); 
    } 

    /** 
    * 
    * @param String flag - the flag for mklink 
    * @param String link - the path and name of the symlink 
    * @param String target - the directory to point the symlink to 
    * @return boolean 
    * @see http://ss64.com/nt/mklink.html 
    */ 
    public boolean createSymlink(String flag, String link, String target) { 
     this.command.clear(); 
     this.command.add("mklink"); 
     this.command.add(flag); 
     this.command.add(link); 
     this.command.add(target); 
     this.currentSymlinks.add(link); 

     return this.runner() == 0; 
    } 

    public boolean removeSymlink(String link) { 
     this.command.clear(); 
     this.command.add("RD"); 
     this.command.add(link); 

     if(this.runner() != 0) { 
      this.command.clear(); 
      this.command.add("DEL"); 
      this.command.add(link); 
     } else { 
      return true; 
     } 

     return this.runner() == 0; 
    } 

    public boolean removeAllSymlinks() { 
     for(String link : this.currentSymlinks) { 
      if(!this.removeSymlink(link)) { 
       return false; 
      } 
     } 

     return true; 
    } 

    /** 
    * Leave for debugging purposes 
    * @return String 
    */ 
    public String getCurrentCommand() { 
     String cmd = ""; 
     for(String part : this.command) { 
      cmd += part + " "; 
     } 

     return cmd; 
    } 

    private int runner() { 
     Process process = null; 
     String message = null; 
     BufferedInputStream bis = null; 
     int exitVal = -1; 
     StringBuilder strBuff = new StringBuilder(); 

     try { 
      if(this.command.size() < 1) throw new Exception("Length of Windows command cannot be zero"); 

      ProcessBuilder pb = new ProcessBuilder(this.command); 
      Map<String, String> envVars = pb.environment(); 

      pb.directory(); 
      pb.redirectErrorStream(true); 
      process = pb.start(); 
      bis = new BufferedInputStream(process.getInputStream()); 
      byte[] bArr = new byte[2048]; 
      while (bis.read(bArr) != -1) { 
       strBuff.append(new String(bArr).trim()); 
       bArr = new byte[2048]; 
      } 

      exitVal = process.waitFor(); 
      message = strBuff.toString(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
      System.err.println(e.getMessage()); 
      System.err.println(message); 
     } 

     return exitVal; 
    } 

    public static void main(String[] args) { 
     WindowsSymlinkUtility foo = new WindowsSymlinkUtility(); 
     foo.createSymlink("%TEMP%\\foo", "C:\\Users\\djthomps\\Downloads"); 
    } 

} 

我得到的錯誤:

java.io.IOException: Cannot run program "mklink": CreateProcess error=2, The system cannot find the file specified 
     at java.lang.ProcessBuilder.start(Unknown Source) 
     at WindowsSymlinkUtility.runner(WindowsSymlinkUtility.java:113) 
     at WindowsSymlinkUtility.createSymlink(WindowsSymlinkUtility.java:56) 
     at WindowsSymlinkUtility.createSymlink(WindowsSymlinkUtility.java:37) 
     at WindowsSymlinkUtility.main(WindowsSymlinkUtility.java:134) 
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified 
     at java.lang.ProcessImpl.create(Native Method) 
     at java.lang.ProcessImpl.<init>(Unknown Source) 
     at java.lang.ProcessImpl.start(Unknown Source) 
     ... 5 more 
Cannot run program "mklink": CreateProcess error=2, The system cannot find the file specified 
null 

一些問題,你可能有:

  1. 你爲什麼要這麼做這個?
    • 由於相關文件和文件夾深深嵌套在文件系統中,因此完整命令的長度超過260個字符。
  2. 如何將符號鏈接幫助?
    • 我做了測試,以確保符號鏈接讓我的「旁路」的260個字符的限制。

這裏是我的問題:

  1. 有另一種方式在Java中創建符號鏈接,這樣,當一個命令超過的260個字符的限制Windows將表現?
  2. SET代替mklink使用嗎?
  3. 是否有可能使用java.nio.file這個即使在運行此命令超過260個字符?

同樣,我明白這是一個奇怪的問題。如有問題要求澄清。

+0

您需要使用mklink程序的'完整路徑'或設置環境變量...即。 'c:\ windows \ system32 \ mklink' java默認不添加windows路徑。 –

+0

@EddieB:什麼環境變量?我認爲Java只是使用PATH,就像其他的一樣? –

+0

問題是createSymlink(鏈接,目標)函數中的拼寫錯誤 - 反斜槓而不是正斜槓,您在其中指定/ J作爲標誌。 –

回答

0

埃迪B的解決方案是在正確的軌道上,但我一直得到錯誤,當Java作爲嘗試運行該命令。這是我的演繹作品:

import java.io.BufferedInputStream; 
import java.io.BufferedReader; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 
import java.util.Arrays; 

public class WindowsSymlinkUtility { 

    public static final String D_LINK = "/D"; 
    public static final String H_LINK = "/H"; 
    public static final String J_LINK = "/J"; 
    public static final String REM_LINK = "rmdir"; 

    private String command, flag, link, target; 
    private List<String> commands = Arrays.asList(D_LINK, H_LINK, J_LINK, REM_LINK), symlinks; 

    public WindowsSymlinkUtility() { 
     this.command = this.flag = this.link = this.target = ""; 
     this.symlinks = new ArrayList<>(); 
    } 

    /** 
    * Automatically creates a directory junction 
    * @param String link - the path and name of the symlink 
    * @param String target - the directory to point the symlink to 
    * @return boolean 
    * @see http://ss64.com/nt/mklink.html 
    */ 
    public boolean createSymlink(String link, String target) { 
     return createSymlink(J_LINK, link, target); 
    } 

    /** 
    * 
    * @param String flag - the flag for mklink 
    * @param String link - the path and name of the symlink 
    * @param String target - the directory to point the symlink to 
    * @return boolean 
    * @see http://ss64.com/nt/mklink.html 
    */ 
    public boolean createSymlink(String flag, String link, String target) { 
     if(!this.commands.contains(flag)) { 
      System.err.printf("%s is not a valid command\n", flag); 
      return false; 
     } 

     this.command = "mklink"; 
     this.flag = flag; 
     this.link = link; 
     this.target = target; 

     if(this.runner() == 0) { 
      this.symlinks.add(this.link); 
      return true; 
     } 

     return false; 
    } 

    private int runner() { 
     Process process = null; 
     String message = null; 
     BufferedInputStream bis = null; 
     StringBuilder strBuff = new StringBuilder(); 
     int exitVal = -1; 

     try { 
      ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", this.command, this.flag, this.link, this.target); 
      Map<String, String> envVars = pb.environment(); 

      pb.directory(); 
      pb.redirectErrorStream(true); 
      process = pb.start(); 
      bis = new BufferedInputStream(process.getInputStream()); 
      byte[] bArr = new byte[2048]; 
      while (bis.read(bArr) != -1) { 
       strBuff.append(new String(bArr).trim()); 
       bArr = new byte[2048]; 
      } 

      exitVal = process.waitFor(); 
      message = strBuff.toString(); 
      System.out.println(message); 
     } catch(Exception e) { 
      e.printStackTrace(); 
      System.err.println(e.getMessage()); 
      System.err.println(message); 
     } 

     return exitVal; 
    } 

    public static void main(String[] args) { 
     (new WindowsSymlinkUtility()).createSymlink(J_LINK, "%TEMP%\\node", "C:\\users\\djthomps\\Downloads"); 
    } 

} 
2

我已經修改了你的程序,提供一個工作示例......本質上問題在於你沒有連接變量並將它們作爲一個參數傳遞給cmd

一個實現說明:: 請勿使用del刪除符號鏈接,否則目標目錄中的所有文件都將被刪除。使用rmdir,我爲後代添加。

/** 
* @author Edward Beckett :: <[email protected]> 
* @since :: 7/21/2015 
*/ 
import java.io.BufferedReader; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.Arrays; 
import java.util.List; 

public class WindowsSymlinkUtility { 

    public static final String D_LINK = "/D"; 
    public static final String H_LINK = "/H"; 
    public static final String J_LINK = "/J"; 
    public static final String REM_LINK = "rmdir"; 
    private String command = ""; 
    private String link = ""; 
    private String target = ""; 

    private List<String> commands = Arrays.asList(D_LINK, H_LINK, J_LINK, REM_LINK); 

    public void createSymlink(String command, String link, String target) { 
     this.command = command; 
     this.link = link; 
     this.target = target; 

     if(!commands.contains(command)) { 
      System.out.println(command + " Is not a valid command \n "); 
      return; 
     } 
     runner(); 
    } 


    private void runner() { 

     try { 

      String[] values = { "CMD", "/C", "mklink", this.command, this.link, this.target }; 
      ProcessBuilder builder = new ProcessBuilder(values); 
      builder.directory(new File(this.link)); 
      Process process = builder.start(); 
      InputStream is = process.getInputStream(); 
      InputStreamReader isr = new InputStreamReader(is); 
      BufferedReader br = new BufferedReader(isr); 
      String line; 
      System.out.printf("Output of running %s is:\n", 
       Arrays.toString(values)); 
      while((line = br.readLine()) != null) { 
       System.out.println(line); 
       int exitValue = process.waitFor(); 
       System.out.println("\n\nExit Value is " + exitValue); 
      } 
     } catch(InterruptedException | IOException e) { 
      e.printStackTrace(); 
     } 
    } 
     public static void main(String[] args) { 
     (new WindowsSymlinkUtility()).createSymlink(J_LINK, "C:\\Foo", "C:\\Temp"); 
    } 

} 

輸出

Output of running [CMD, /C, mklink, /J, C:\Foo, C:\Temp] is: 
Junction created for C:\Foo <<===>> C:\Temp 
Exit Value is 0 
+0

呵呵,所以我嘗試了幾種不同的方法:1.(new WindowsSymlinkUtility())。createSymlink(J_LINK,「C:\\ temp」,「C:\\ Users \\ djthomps \\ Downloads \\」) ;'2。'(new WindowsSymlinkUtility())。createSymlink(J_LINK,「C:\\ temp \\ node」,「C:\\ Users \\ djthomps \\ Downloads \\」);'我不是得到任何輸出說明符號鏈接實際上是創建的。在這個確切的用例中,我只想在'node.exe'目錄之間創建一個符號鏈接。第一次使用時出錯:'java.io.IOException:無法運行程序「CMD」(在目錄「C:\ temp \ node」中):CreateProcess error = 267,目錄名無效' – djthoms

+0

Ran out of房間。運行[CMD,/ C,mklink,/ J,C:\ temp,C:\ Users \ djthomps \ Downloads \]是'編輯:'mklink/JC:\ temp \ node C後, :\ Users \ djthomps \ Downloads'運行此命令的工作原理 – djthoms

+0

您的問題是添加尾隨目錄斜槓(s)。 –

相關問題