check that file exists after call

edited January 2018 in Questions about Code

I call a utility and copy the output to a text file then read the text file. The file is created ok, but when i read it with loadStrings its not all there unless i include a delay of =>600 even though i erase the old file and create a new one and wait for it to appear Why doesn't the file checking work?

// read properties

     final File f2 = dataFile(STILLPROP_PATH);
     if(f2.exists()) { f2.delete(); }
     open("c:/avspit/stillcap /listproperties > c:/avspit/stillprop.txt");
     delay(600);
     while (!f2.exists()) { s+="."; 
     delay(300); // Avoids frying CPU!
     //println(s);                
     }

Answers

  • I'm not sure what you're trying to do when you delete the file and then recreate it, but the cause of the problem is that file output happens asynchronously. To make sure it finishes, you should call the flush() and close() functions on the writer before trying to read the file.

    From the reference:

    PrintWriter output;
    
    void setup() {
      // Create a new file in the sketch directory
      output = createWriter("positions.txt"); 
    }
    
    void draw() {
      point(mouseX, mouseY);
      output.println(mouseX + "t" + mouseY); // Write the coordinate to the file
    }
    
    void keyPressed() {
      output.flush(); // Writes the remaining data to the file
      output.close(); // Finishes the file
      exit(); // Stops the program
    }
    
  • edited January 2018 Answer ✓

    As long that util code is run from another Thread, there's no shame on relying on delay() in order to await for that file to be reborn. :\">

    I don't have and neither got any idea what is that "stillcap"; but here's my blind attempt at it: >-)

    // Forum.Processing.org/two/discussion/25826/
    // check-that-file-exists-after-call#Item_2
    
    // GoToLoop (2018-Jan-04)
    
    static final String PROP_PATH = "c:\\avspit\\";
    static final String PROP_FILE = PROP_PATH + "stillprop.txt";
    static final String CMD = PROP_PATH + "stillcap /listproperties > " + PROP_FILE;
    
    static final int DELAY = 5;
    
    final File propFile = dataFile(PROP_FILE);
    volatile boolean exists;
    
    void recreateFile() {
      if (propFile.exists())  propFile.delete();
      exists = false;
      open(CMD);
      while (!propFile.exists())  delay(DELAY);
      exists = true;
    }
    
    void setup() {
      size(300, 200);
      thread("recreateFile");
    }
    
    void draw() {
      frame.setTitle("Exists: " + exists);
    }
    
  • Stillcap is a command line utility .exe that i call with open.

    It outputs text which i port with > to a stillprop.txt file in the open string

    each time the program runs i want to delete the old stillprop.txt and create a new

    one using open to cal stillcap utility

    I want the program to wait until the new stiiprop.txt file is written to

    disk and exists before continuing.

    I can use a delay with some number but that delay value may be different on

    different PC's. By checking for the file to appear the program only waits

    as long as necessary then goes on.

    I then load the file into a string array and parse the info i need to check

    to see if certain parameters are set.

    So , assuming a file already exists, i found this code for deleting the existing file

    and then checking it exists again after the open call writes a new one.

    So is the problem that the delete may not delete the file before it is

    rewritten? Basically I'm just trying the make sure the call completes before

    the program continues. If i don't, the loadString gives an error that the file is

    missing

    thanks

  • edited January 2018 Answer ✓
    • In my example, I've declared a variable called exists.
    • If you invoke recreateFile() via thread(): https://Processing.org/reference/thread_.html
    • You just need to keep continuously polling that variable exists until it becomes true.
    • Then you know the whole delete() + open() has completed.
    • Another option is simply invoking recreateFile() directly.
    • Under this 2nd approach, the program is gonna halt until the whole task is finally finished.
    • Just choose the approach you prefer. Both should work alright. :-bd
  • thks ! glad your here! question : "c:\avspit\" why double slashes? I have just been using single forward slashes in side the quotes. Could that be causing a issue?

  • edited January 2018 Answer ✓
    • Under Windows OS, backslash \ is the separator character for folders.
    • In order to have them inside quotes "", b/c backslash \ is already used for special coding such as \n, we have to type in them as \\.
    • Normally, Processing & Java API automatically convert regular / to \ when code is run under Windows.
    • However, when dealing w/ command line strings arguments passed to functions such as open(), just maybe we've gotta make sure that all / characters are converted to \ under Windows.
    • But most probably, the "c:/avspit/" string should work just fine w/o using double backslashes \\ like I did in my example: "c:\\avspit\\".
  • edited January 2018 Answer ✓
    • Seems like open() isn't available for Processing 3.
    • And I had to code my example under Processing 2.
    • About half year ago, I've modified a library which deals w/ command lines too.
    • I've modified it in such a way that it is now a pure Java library w/o any 3rd party imports.
    • If you wish, you can try that out in place of Processing 2's open():
      https://GitHub.com/GoToLoop/command/blob/patch-1/src/deadpixel/command/Command.java
    • I believe It should work for all Processing versions. Actually, for any Java code. ~O)
    • You can import it to your code like this: import deadpixel.command.Command;
    • And instantiate it by passing your command line string to it: Command cmd = new Command("");.
    • Then call its run() method: cmd.run();
    • Better yet, also println() its boolean result: println("Success:", cmd.run(), ENTER);
    • So you will know whether or not the command line string has completed successfully.
    • Differently from Processing 2's open(), Command::run() method blocks the execution thread.
    • So the program awaits until Command::run() completes. :ar!
  • thks again!

  • i've only added contributed libraries inside the pde with import libary to add an external library i download the command folder from github and put it in its own library folder , then i will find it from the pde when i goto import libraries?

    \documents\processing\libraries\library\command

  • edited January 2018 Answer ✓
    • You don't need to make it available as a 3rd-party library.
    • Just place the "Command.java" file in your sketch folder, alongside your ".pde" file.
    • Another option is to drag & drop the ".jar" in your sketch, so a subfolder "code/" is automatically created.
    • However, if you prefer it as a globally available library, create a subfolder inside your "library/" subfolder.
    • Its name gotta match the ".jar" file though. So, that sufolder's name needs to be: "Command/".
    • Inside "Command/", create another subfolder called "library/", and place the "Command.jar" file there.
    • Optionally, create a "src/" subfolder too and place the other 2 files there: "Command.java" & "Command.py".
  • Still get error that file does not exist.

    Here is the scenario:

    The file gets deleted ok. then open calls the outside function It creates the file and writes it to disk.

    The exists while loop works , i know this because I have a string that a "." gets added to and printed to the console indicating how many loops the while does until it "sees" the file on the disk and exist becomes true.

    The next instruction is a loadImage of the file.

    If i do not put a delay after the while loop has recognized the file exists I get an error that the file does not exist!

    If i put a delay of 100, it works sometimes A delay of 300 seems to work consistently.

    But i do not understand why if the while loop is working and does not allow the program to continue until it sees the file, that this happens.

    I put the delete file,while ! exists and open loop in a function and call that from the draw loop. I return from the function once the file exists, then loadImage and the load Image fails unless there is a delay added before it in draw after the call back from the function. or a delay at the end of the function call after the while exists loop is true.

    I have run it continuously and i noticed the dots i get for the while loop are usually 3-4 and then it exits because the file exists. But occasionally it give 10-20 dots , taking longer . Which is fine as long as once the exists is true the loadImage would work after

    BAFFLED!

    any help for such a simple but necessary verification chk of a new file written to disk would be appreciated

  • edited January 2018 Answer ✓
    • Perhaps what's happening is that the external program is still working on the newly created file when your sketch attempts to use that prematurely. :|
    • If that's the case, calling exists() isn't enough. The File may still be incomplete! :-&
    • That's why I've recommended you to use that "Command.java" library b/c it awaits for the external program to fully finish. $-)
  • is there a way to catch the runtime error " missing or inaccessible" in the running program and try to reload the file again with loadImage until this error doesn't happen?

  • does it throw an actual exception?

    if so put a try catch around it, catching a generic Exception. call it e.

    e.printStackTrace will tell you the exact exception it's throwing so you can act on that specifically.

    BUT part of me thinks it won't throw an exception, just log an error and leave the image as null. so you might have to check that as well.

    oh, and please don't post duplicates.

  • edited January 2018
    • Most of Processing's API internally "swallows" thrown exceptions.
    • It means sketches don't stop for most of runtime errors while using Processing API. @-)
    • In the event they aren't swallowed, we can catch () them by placing those calls inside a try {} block.
    • But what I don't get is why would you prefer such headache rather than using a library which already awaits the external program to finish fully. :|
  • just stubborn I guess , would like to have processing just work correctly without all the addons. I have downloaded command and will start using , see if it solves issues. Thanks.

  • Much probably P2's open() returns a Process object:
    https://Docs.Oracle.com/javase/9/docs/api/java/lang/Process.html

    And you can do the same stuff "Command.java" code does, like calling waitFor():
    https://Docs.Oracle.com/javase/9/docs/api/java/lang/Process.html#waitFor--

  • edited January 2018

    Change external script to write to a temp file.

    Rename the temp file (still in the external script) to the proper filename when it's finished.

    Your main program should then never see a half-written file.

Sign In or Register to comment.