1

I have a Java application that will be used both from the Windows Command Prompt and the Cygwin terminal. The program uses and manipulates file paths. It we be very useful to have a sep variable that would be / when the program is launched from Cygwin but \\ when the program is launched from Windows.

Looking here, I'm not sure it will be possible, but I want to ask.

I will post a small, compilable app that shows the issue in a few minutes. For now, I'll just say that I want a set of functions that something like:

// 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()

Thanks @Raphael_Moita. Those are very useful, and I will likely use them in the Linux version of the app that I will be using. @Luke_Lee, I feel dumb not having realized it. I think you two might have solved my problem while I was getting the compilable code ready. There's still one issue when the program run from a batch script - when it is fed a filename from a find command. I hope what I show will illustrate that.

Examples

All examples are as run from Cygwin.

Works: the way most volunteers use the code, just the filename that's in the same directory as the java code.

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

Works: with relative filepaths and spaces in filenames/file paths

$ 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

DOESN'T WORK. Sometimes, the output of a find command will come with the complete filepath in Cygwin/UNIX format:

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

Compilable Code

I'm just cutting down from my original code, so I'm sorry if it seems too big.

/**********************************
 * @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
Community
  • 1
  • 1
bballdave025
  • 1,347
  • 1
  • 15
  • 28
  • Before someone asks, I do know about `cygpath`. If I knew the file path were going to be fed in using a UNIX-style path, I could use: `java $(cygpath -wp )` That will not work in my case. At any rate, it wouldn't make sense, since those who will be using the program from Cygwin would not have a problem needing to convert their UNIX-style path to a Windows-style path. – bballdave025 Nov 29 '16 at 23:11
  • 2
    You can always use `/`. – xiaofeng.li Nov 29 '16 at 23:19

2 Answers2

3

You don't need to know which SO is under your Java. If your goal is to find the correct file separator to use, call this:

java.io.File.separator;

Anyway ... to find out which SO java is running over (not sure how cygwin is detected by this), try:

boolean isWindows = System.getProperty("os.name").startsWith("win");
  • 1
    These are great suggestions. The `isWindows` will be especially useful as I run the code myself on Linux. The one problem is that `java.io.File.separator;` returns `\\` even when run from the Cygwin terminal. It doesn't quite answer my question, which is why I'm not choosing it as the preferred answer, but then again, I hadn't completely asked my question. Thanks so much! – bballdave025 Nov 30 '16 at 01:10
  • I've been thinking this over today, and you're absolutely correct; I don't need to know which OS is under my Java. I could just strip off the `/cygwin/c` from the filename argument (if the `/cygwin/c` part exists.) The only problem there comes when the filename argument comes from a different drive - maybe a public, mounted drive `/cygdrive/p`. I didn't mention that in my original post. – bballdave025 Dec 01 '16 at 02:30
  • I do, however, want to know which terminal/prompt my Java was launched from. – bballdave025 Dec 01 '16 at 02:30
0

Here is an answer I've come up with that almost answers my original question. It tries to determine the launcher of the Java code based on the filename argument. A big thanks to @Raphael_Moita and @Luke_Lee, who actually pretty much solved my problem. Their solutions didn't answer the original question, but that's partly because I didn't post the original question completely. As I said, this answer doesn't answer the original question completely. If someone knows the complete solution, please let me know.

My solution was a few methods. As they stand, they only work for my case - Cygwin on Windows. (What they do is tell you if the filename argument for the Java application was consistent with being launched from Windows cmd or not.) I plan on posting a more portable group of methods, i.e. other Operating Systems.

I'm sure there are issues. Please point them out to me.

// 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)

Parts of this solution are due to @Raphael_Moita and @Luke_Lee, but I also need to reference this SO post. This last one helped with my specific situation, where the files are not all hosted on the C:\ drive.

Note I won't be accepting mine as the correct solution, because it doesn't answer my original question. I hope it might help someone with answering the original question.

Community
  • 1
  • 1
bballdave025
  • 1,347
  • 1
  • 15
  • 28