How to save files to the data folder without needing an absolute path.

edited September 2016 in How To...

OK, maybe I'm making a big deal over nothing, I'm fairly new to Processing but -- loadStrings() expects to load a user-defined file from the current sketch's "data" folder , right? But saveStrings() does not SAVE to that folder, it goes out to the main sketch folder. SO if you want your program to load a file, modify it, and then resave it back to the data folder, you are forced to use an absolute path for saving, thus kinda blowing your portability, or at least forcing you to write a custom file saving routine. Am i wrong about this? Is there some easy way to direct your Sketch to actually save your data to the data forder? And if not, why the heck not? Is there some point to doing it this way?

Tagged:

Answers

  • edited September 2016

    Use saveStrings(dataPath("name_of_the_file"));. *-:)

  • edited September 2016

    loadStrings() expects to load a user-defined file from the current sketch's "data" folder, right?

    Actually it 1st checks out the root's sketchPath. Only otherwise go to its "data/" subfolder. L-)

    Oops! That's the opposite, as @jeremydouglass has pointed out! X_X

    println(loadStrings("WhichFolder.txt")); // [0] "From Data!"
    exit();
    
  • edited September 2016

    Not quite true, GoToLoop - on a bare filename loadStrings() first checks dataPath, then sketchPath.

    rickhatfield, I can see why this is confusing -- the saveStrings() reference says

    By default, this file is saved to the sketch's folder.

    and the [loadStrings() reference (https://processing.org/reference/loadStrings_.html) says

    If the name of the file is used as the parameter, as in the above example, the file must be loaded in the sketch's "data" directory/folder. Alternatively, the file maybe be loaded from anywhere on the local computer using an absolute path

    That "must" isn't actually true. In practice, anything you do to save, you can do to load, and the pairs almost always match -- if on save you specify a bare filename, or a partial path, or a full path, then on load you can do the same thing and retrieve what you saved.

    There is one "gotcha": if you have files with the same name in /data and in the sketchpath, the data file will be loaded first. This default is the only time that load and save syntax won't match in a visually intuitive way.

    saveStrings("duplicate.txt", new String[]{"I'm in the sketch path", ""});
    saveStrings(dataPath("duplicate.txt"), new String[]{"I'm in the data path", ""}); 
    String[] duplicateResults = loadStrings("duplicate.txt"); //// THIS LOADS FROM DATA, NOT SKETCH
    

    Here is a testing sketch for playing with saves/loads -- it can be adapted to work with other processing save/load pairs.

    /**
     * String Saving and Loading
     * 2016-09-10 Jeremy Douglass
     * Processing 3.2.1 -- tested on OS X 10.10.5
     * 
     */
    
    String lineData1[] = {"apple banana", "cherry"};
    String lineData2[] = {"foo bar", "baz"};
    String lineData3[] = {"lorem ipsum", "sit"};
    String lineData4[] = {"head shoulders", "knees"};
    String sketchPathData[] = {"I'm text in the sketch path", ""};
    String dataPathData[]   = {"I'm text in the data path", ""};
    
    void setup(){
      println("** Save and load a bare filename: **");
      saveAndLoadStrings("fileNameOnly.txt", lineData1);
    
      println("** Save and load using dataPath:* *");
      saveAndLoadStrings(dataPath("fileInDataPath.txt"), lineData2);
    
      println("** Save and load using a relative path prefix (data): **");
      saveAndLoadStrings("data/fileWithDataPrefix.txt", lineData3);
    
      println("** Save and load using a relative path prefix ** \n(anything other than data, even if folder doesn't exist):");
      saveAndLoadStrings("other/fileWithDataPrefix.txt", lineData4);
    
      println("** What if a filename 'duplicate.txt' is saved in both sketch folder and /data? **");
      saveStrings("duplicate.txt", new String[]{"I'm in the sketch path", ""});
      saveStrings(dataPath("duplicate.txt"), new String[]{"I'm in the data path", ""}); 
      String[] duplicateResults = loadStrings("duplicate.txt"); //// THIS LOADS FROM DATA, NOT SKETCH
      print("Loading 'duplicate.txt' shows:\n     "); println(duplicateResults);
    }
    
    String[] saveAndLoadStrings (String filename, String[] fileData){
      saveStrings(filename, fileData);
      String[] loaded = loadStrings(filename);
      print("Save/Loading: "); println(filename);
      print("     Saving:  "); println(fileData[0]);
      print("     Loading: "); println(loaded[0]);
      println();
      return loaded;
    }
    

    ...the output looks like this:

    ** Save and load a bare filename: **
    Save/Loading: fileNameOnly.txt
         Saving:  apple banana
         Loading: apple banana
    
    ** Save and load using dataPath:* *
    Save/Loading: /Users/yourusername/Documents/Processing/StringSavingAndLoading/data/fileInDataPath.txt
         Saving:  foo bar
         Loading: foo bar
    
    ** Save and load using a relative path prefix (data): **
    Save/Loading: data/fileWithDataPrefix.txt
         Saving:  lorem ipsum
         Loading: lorem ipsum
    
    ** Save and load using a relative path prefix ** 
    (anything other than data, even if folder doesn't exist):
    Save/Loading: other/fileWithDataPrefix.txt
         Saving:  head shoulders
         Loading: head shoulders
    
    ** What if a filename 'duplicate.txt' is saved in both sketch folder and /data? **
    Loading 'duplicate.txt' shows:
         I'm in the data path 
    
  • Your reply raises more questions than it answers. What is "dataPath" and WHY, in the name of all that's egregiously murky, is it not in the language reference???

  • ... ,is it not in the language reference???

    Unfortunately many useful API isn't published at Processing's reference page! :-<
    Moreover, there are some reference mistakes and omissions too! :-&

  • edited September 2016

    Your reply raises more questions than it answers.

    That seems... uncharitable, Rick. You asked "How to save files to the data folder without needing an absolute path" and I shared three different ways of doing saving files to the data folder without needing an absolute path. Perhaps you would like to enumerate some of these many questions that I should have been answering, but instead raised?

    String fileData[] = {"a b", "c"};
    saveStrings("data/myfile.txt", fileData);
    String[] loaded = loadStrings("data/myfile.txt");
    

    Re: "egregiously murky", I think you may not have the right expectations of the reference. Processing is, as the site says "a flexible software sketchbook and a language for learning how to code within the context of the visual arts." This means the reference is aimed at beginners, and aims to explain a simplified subset of the things Processing can do.

    As my demo showed you, there is no need for you to use dataPath(). For power users (such as GoToLoop), the Processing Javadoc documents many things which are not in the beginner's reference. I happen to agree with GoToLoop that there are many things I would love to see added or corrected in the reference, but I don't think that dataPath() is a good example -- you can save and load from /data just fine without it. While leaving things out makes the reference less useful for power users, on the positive side it makes the reference clearer and less overwhelming for first time coders (who are Processing's core audience). Some advanced entries in the reference also link to the Javadoc for those wanting more detail -- see for example the PShape entry. Finally, if you really need to know exactly how something works, the Processing source code is available on GitHub. While I wouldn't recommend these to you if your goal is to learn coding for the first time with Processing, I hope these resources make things less murky if you need them.

  • edited September 2016

    ... but I don't think that dataPath() is a good example...

    When we drag files onto Processing's IDE, it automatically creates the "data/" subfolder and copies that file into it.

    All loading functions 1st check out "data/" subfolder. But when it comes to saving files, it goes into the root folder instead??? 8-}

    Very bad inconsistency and also confusing to beginners! ~X(

    It's too l8 to change that ugly default behavior. But still it'd be nice to include some hint() for changing that at least. *-:)

    But till then, I'd be happy if at least dataPath() (and maybe dataFile() too) would get its own entry at the official API reference; so more folks would learn about it and have less come here to re-ask that... I-)

  • Yes, Jeremy, that was uncharitable of me, and I apologize. I'm a bit autistic and sometimes unintentionally rude, impatient, & exaggerated. But you are very kind to provide that information. It would probably be entirely adequate if I were a more proficient programmer. I will just have to work my way through it and figure out which option I need. But I must say that, at least for an amateur such as myself, one is given the impression that that reference page is a complete listing of all one should need. I have never seen ANY mention of those other resources. I'm very glad to know there are some, as the documentation has so far sometimes left something to be desired.

  • Rick -- absolutely understood, thank you for explaining. You make a very good point that the Javadoc and code (or even the fact that it exists) seems secret and mostly hidden by the reference. I have experienced the need to rediscover it myself when coming back to Processing, and I don't see a clear link to the Javadoc in the menus on processing.org.

    GoToLoop -- I totally see what you are saying. I don't disagree that the inconsistency can be confusing, both in the reference and in practice -- that's why I tried to highlight it as a "gotcha." I'd love to see better documentation. I'm just pointing out that working the problem by using dataPath() isn't something that will affect the vast majority of new sketch users.

    Even if a user does this:

    1. drag a file "1.txt" into the IDE
    2. move a file "2.txt" into the sketch folder
    3. move a file "3.txt" into the data folder
    4. runs saveStrings("3.txt", fileData);
    5. runs saveStrings("data/4.txt", fileData);

    ...or any weird combination of all these things, then this will still work for them:

    String[] load1 = loadStrings("1.txt");
    String[] load2 = loadStrings("2.txt");
    String[] load3 = loadStrings("3.txt");
    String[] load4 = loadStrings("4.txt");
    String[] load5 = loadStrings("5.txt");
    

    I believe it is only if the user loads two different files with the same name into both folders that datapath() becomes relevant to a beginner problem. That's a pretty specific edge case for a beginner.

Sign In or Register to comment.