Быстро определить, была ли Java запущена из командной строки Windows или терминала Cygwin.

У меня есть приложение Java, которое будет использоваться как из командной строки Windows, так и из терминала Cygwin. Программа использует и манипулирует путями к файлам. Было бы очень полезно иметь переменную sep, которая была бы / при запуске программы из Cygwin и \\ при запуске программы из Windows.

Глядя здесь, я не уверен, что это будет возможно, но я хочу спросить.

Я опубликую небольшое компилируемое приложение, которое покажет проблему через несколько минут. А пока я просто скажу, что мне нужен набор функций, что-то вроде:

// in main
...
String sep = getSeparatorToUse();
...

// member functions
...
private boolean wasLaunchedFromWinCmd() 
{
  if (<something-here-that-knows-it-was-cmd-not-cygwin>)
    return true;

  return false;

}//endof:  private boolean wasLaunchedFromWinCmd()

private String getSeparatorToUse()
{
  if (wasLaunchedFromWinCmd)
    return "\\"

  return "/"

}//endof:  private String getSeparatorToUse()

Спасибо @Raphael_Moita. Это очень полезно, и я, скорее всего, буду использовать их в версии приложения для Linux, которую буду использовать. @Luke_Lee, я чувствую себя глупо, не осознавая этого. Думаю, вы двое могли бы решить мою проблему, пока я готовил компилируемый код. Есть еще одна проблема, когда программа запускается из пакетного скрипта - когда ей передается имя файла из команды find. Надеюсь, то, что я покажу, проиллюстрирует это.

Примеры

Все примеры запускаются из Cygwin.

Работает: так же, как большинство добровольцев используют код, просто имя файла находится в том же каталоге, что и java-код.

$ java FileSeparatorExample pic_4.jpg
Here, something will be done with the file,
C:\Users\bballdave025\Desktop\pic_4.jpg

Работает: с относительными путями к файлам и пробелами в именах файлов/путях к файлам

$ java FileSeparatorExample pretty\ pictures/pic\ 1.jpg
Here, something will be done with the file,
C:\Users\me\Desktop\pretty pictures/pic 1.jpg

$ java FileSeparatorExample ../pic_5.jpg
Here, something will be done with the file,
C:\Users\me\Desktop\../pic_5.jpg

НЕ РАБОТАЕТ. Иногда вывод команды find будет содержать полный путь к файлу в формате Cygwin/UNIX:

$ java FileSeparatorExample /cygdrive/c/David/example/pic.jpg
The file:
C:\Users\bballdave025\Desktop\/cygdrive/c/David/example/pic.jpg
doesn't exist

Компилируемый код

Я просто сокращаю исходный код, поэтому извините, если он кажется слишком большим.

/**********************************
 * @file FileSeparatorExample.java
 **********************************/

// Import statements
import java.io.File;
import java.io.IOException; 

public class FileSeparatorExample
{ 
  // Member variables
  private static String sep;


  public static void main(String[] args) 
  {
    ////****** DOESN'T WORK AS DESIRED ******////
    sep = java.io.File.separator;
    ////** I want **////
    // sep = getFileSeparator();

    String imageToLoad = null;
    boolean argumentExists = ( args != null && args.length != 0 );

    if (argumentExists)
    {
      boolean thereIsExactlyOneArgument = ( args.length == 1 );
      if (thereIsExactlyOneArgument)
      {
        imageToLoad = args[0];
      }//endof:  if (thereIsExactlyOneArgument)
      else
      {
        // do some other stuff
      }

    }//endof:  if (argumentExists)

    String filenamePath = getFilenamePath(imageToLoad);
    String filenameFile = getFilenameFile(imageToLoad);

    imageToLoad = filenamePath + sep + filenameFile;

    File f = new File(imageToLoad);
    if (! f.exists())
    {
      System.err.println("The file:");
      System.err.println(imageToLoad);
      System.err.println("doesn\'t exist");  

      System.exit(1);

    }//endof:  if (! f.exists())

    System.out.println("Here, something will be done with the file,");
    System.out.println(imageToLoad);

  }//endof:  main


  // member methods
  /**
   * Separates the filename arg into: full path to directory; bare filename
   */
  private static String[] splitFilename(String imageToLoad)
  {
    String[] fileParts = new String[2];

    int indexOfLastSep = imageToLoad.lastIndexOf(sep);
    boolean fullFilenameHasSeparator = ( indexOfLastSep != -1 );
    if (fullFilenameHasSeparator)
    {
      fileParts[0] = imageToLoad.substring(0, indexOfLastSep);
      fileParts[1] = imageToLoad.substring(indexOfLastSep + 1);

    }//endof:  if (fullFilenameHasSeparator)
    else
    {
      // Use the user's directory as the path
      fileParts[0] = System.getProperty("user.dir");
      fileParts[1] = imageToLoad;

    }//endof:  if/else (fullFilenameHasSeparator)

    return fileParts;

  }//endof:  private static String[] splitFilename(String imageToLoad)

  /**
   * Gives the full path to the file's directory (from the filename arg)                       
   * but not the bare filename
   */
  private static String getFilenamePath(String imageToLoad)
  {
    String[] fileParts = splitFilename(imageToLoad);
    return fileParts[0];

  }//endof:  private static String getFilenamePath(String imageToLoad)


  /**
   * Gives the bare filename (no path information)
   */
  private static String getFilenameFile(String imageToLoad)
  {
    String[] fileParts = splitFilename(imageToLoad);
    return fileParts[1];

  }//endof:  private static String getFilenamePath(String imageToLoad)

}//endof:  public class FileSeparatorExample

person bballdave025    schedule 29.11.2016    source источник
comment
Прежде чем кто-то спросит, я знаю о cygpath. Если бы я знал, что путь к файлу будет передан с использованием пути в стиле UNIX, я мог бы использовать: java $(cygpath -wp <file-argument>) В моем случае это не сработает. Во всяком случае, это не имело бы смысла, поскольку у тех, кто будет использовать программу из Cygwin, не возникнет проблем с необходимостью конвертировать свой путь в стиле UNIX в путь в стиле Windows.   -  person bballdave025    schedule 30.11.2016
comment
Вы всегда можете использовать /.   -  person xiaofeng.li    schedule 30.11.2016


Ответы (2)


Вам не нужно знать, какой SO находится под вашей Java. Если ваша цель — найти правильный разделитель файлов, вызовите его:

java.io.File.separator;

В любом случае... чтобы узнать, какая SO java работает (не знаю, как это обнаруживает cygwin), попробуйте:

boolean isWindows = System.getProperty("os.name").startsWith("win");
person VeryNiceArgumentException    schedule 29.11.2016
comment
Это отличные предложения. isWindows будет особенно полезен, поскольку я сам запускаю код в Linux. Одна проблема заключается в том, что java.io.File.separator; возвращает `\` даже при запуске из терминала Cygwin. Это не совсем отвечает на мой вопрос, поэтому я не выбираю его в качестве предпочтительного ответа, но опять же, я не полностью задал свой вопрос. Спасибо большое! - person bballdave025; 30.11.2016
comment
Я думал об этом сегодня, и вы абсолютно правы; Мне не нужно знать, какая ОС находится под моей Java. Я мог бы просто удалить /cygwin/c из аргумента имени файла (если часть /cygwin/c существует). Единственная проблема возникает, когда аргумент имени файла поступает с другого диска — может быть, с общедоступного смонтированного диска /cygdrive/p. Я не упомянул об этом в своем исходном посте. - person bballdave025; 01.12.2016
comment
Однако я хочу знать, с какого терминала/приглашения была запущена моя Java. - person bballdave025; 01.12.2016

Вот ответ, который я придумал, и он почти отвечает на мой первоначальный вопрос. Он пытается определить средство запуска кода Java на основе аргумента имени файла. Большое спасибо @Raphael_Moita и @Luke_Lee, которые в значительной степени решили мою проблему. Их решения не отвечали на исходный вопрос, но отчасти это потому, что я не полностью опубликовал исходный вопрос. Как я уже сказал, этот ответ не полностью отвечает на исходный вопрос. Если кто-то знает полное решение, пожалуйста, дайте мне знать.

Моим решением было несколько методов. В их нынешнем виде они работают только для моего случая — Cygwin для Windows. (Что они делают, так это сообщают вам, соответствует ли аргумент имени файла для приложения Java запуску из Windows cmd или нет.) Я планирую опубликовать более переносимую группу методов, то есть другие операционные системы.

Я уверен, что есть проблемы. Пожалуйста, укажите их мне.

// in main
...
sep = java.io.File.separator; // Thanks @Luke_Lee
if (args != null && args.length != 0)
  sep = getSeparatorToUse(args[0]);
...

// member functions
...
private boolean wasLaunchedFromWinCmd(String firstArg)
{
  boolean isWindows = System.getProperty("os.name").startsWith("win");
  if (! isWindows)  return false; // Thanks @Raphael_Moita
  else
  {
    String launchDir = System.getProperty("user.dir");
    String rootOfLaunchDir = getRoot(launchDir);
                  // This will come back with something like "C:\" or "P:\"

    String rootOfArgument = getRoot(firstArg);

    if (rootOfArgument.equals("/"))
    {
      String cygwinBase = "/cygdrive/";

      char letterOfRoot = rootOfLaunchDir.charAt(0);
                  // For, e.g., "/Users/me/Desktop/pic_314.jpg"

      if (firstArg.startsWith(cygwinBase))
      {
        int charsToCut = cygwinBase.length();
        letterOfRoot = firstArg.substring(charsToCut, 
                                          charsToCut + 1);

      }//endof:  if (firstArg.startsWith(cygwinBase))

      System.out.println("The root directory of your argument will be:");
      System.out.println(Character.toUpperCase(letterOfRoot) + ":\\");
      System.out.println("In Cygwin, that will be:");
      System.out.println(cygwinBase + 
                         Character.toLowerCase(letterOfRoot) + "/");

      return false;
        // Not always correct, e.g. if someone in Cygwin uses
        // $ java FileSeparatorExample "C:\pic_137.jpg"

    }//endof:  if (rootOfArgument.equals("/"))

    return true;

  }//endof:  if/else (! isWindows)

}//endof:  private boolean wasLaunchedFromCmd()


private String getRoot(String fileOrDir)
{
  File file = new File(fileOrDir).getAbsoluteFile();
  File root = file.getParentFile();
  while (root.getParentFile() != null)
    root = root.getParentFile();

  return root.toString();

}//endof:  private String getRoot();


private String getSeparatorToUse(String firstArg)
{
  if (wasLaunchedFromWinCmd(firstArg))
    return "\\"

  return "/"

}//endof:  private String getSeparatorToUse(String firstArg)

Части этого решения принадлежат @Raphael_Moita и @Luke_Lee, но мне также нужно сослаться на это сообщение SO. Последнее помогло в моей конкретной ситуации, когда не все файлы размещены на диске C:\.

Примечание. Я не буду принимать свое решение как правильное, потому что оно не отвечает на мой первоначальный вопрос. Я надеюсь, что это может помочь кому-то ответить на исходный вопрос.

person bballdave025    schedule 01.12.2016