2015-07-21 77 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)。 –