Write to JSON File

Is there an analog to the String.parseJSON for writing? I guess I could make a fancy format string that would write the things i want to, but it would be nice to take a Dictionary and ship it to the filesystem directly.

Edit: actually, it doesn’t have to be JSON. I’m looking to store some synth configs (and maybe make it easy to load presets). And JSON seemed like a good idea. But anything else that would enable me to save and load some numbers would work.

Something like this?

d= Dictionary.newFrom([\a, 3, \b, 2, \c, 1]);
f = File("~/test.json".standardizePath,"w");
f.write(d.asJSON);
f.close;

SuperCollider makes it really easy to store things inside files and get them back.

Instead of “File.read”, which manipulates a string, you can also execute the file to get the content back directly, if you stored the data using .asCompileString :

(
// You can't do this if the file is not saved
var currentFolder = thisProcess.nowExecutingPath.dirname ++ "/";

// Datas stored inside an IdentityDictionary
var saveDatas = (
	foo: 5,
	bar: "test"
);

var saveFile, loadDatas;

// Saving the ID inside a file
saveFile = File(currentFolder ++ "saveFile.scd", "w");
saveFile.write(saveDatas.asCompileString);
saveFile.close;

// Retrieving the ID back
loadDatas = this.executeFile(currentFolder ++ "saveFile.scd");
loadDatas.postln;
loadDatas[\foo].postln;
// No conversion needed, this isn't a string, it's an ID dict (it's an Event, but it's the same)
loadDatas.class.postln;
)
3 Likes

Please note, if this makes sense to you, that you can use this to create new instances of an object prototype. This might help organizing the code/project, and allows you to quickly copy-paste an object prototype from a project to an other, or to dynamically load them :

(
var currentFolder = thisProcess.nowExecutingPath.dirname ++ "/";

// Object Prototype
var calculatorProto = (
	square: { |self, number|
		number * number
	},
);

var protoFile, instance;

// Saving the ID inside a file
protoFile = File(currentFolder ++ "calculatorProto.scd", "w");
protoFile.write(calculatorProto.asCompileString);
protoFile.close;

// Creating a new instance
instance = this.executeFile(currentFolder ++ "calculatorProto.scd");
instance.square(4).postln;
)
1 Like

The following code is my attempt.
The code does not support array. You will need to modify the code including adding some lines to parse array.

(
~asJson =  { |dictionaryOrEvent|
	var txt, func;
	txt = "{\n";
	func = { |item, depth=0|
		var keys, tab;
		keys = item.keys.asArray.sort;
		(depth + 1).do{ tab = tab ++ "\t" };
		keys.do { |thisKey, index|
			var subDepth;
			subDepth = depth + 1;
			txt = txt ++ tab ++ thisKey.asString.quote ++ ":";
			if ("Event|Dictionary".matchRegexp(item[thisKey].class.asString)) {
				txt = txt + "{\n";
				func.(item[thisKey], subDepth);
				txt = txt ++ tab ++ "},\n"
			} {
				txt = txt + item[thisKey];
				txt = txt ++
				if (index == (keys.size - 1)) {
					"\n"
				} {
					", \n"
				}
			}
		}
	};
	func.(dictionaryOrEvent);
	txt ++ "}"
}
)

d = Dictionary.newFrom([\a, 3, \b, 2, \c, 1]);
e = (a: (aa: 2, ab: 3), b: 5, c: 4);
g = (a: (aa: 2, ab: 3), b: Dictionary.newFrom([\ba, 3, \bb, 2, \bc, 1]);, c: 4);
h = (a: [(aaa: 2, aab:3), (aba: 2, abb:3)])

~asJson.(d)
~asJson.(e)
~asJson.(g)

~asJson.(h) // not transcribed


~jsonFile = "~/Downloads/test.json".standardizePath

~writeJSON = File(~jsonFile, "w+");
~writeJSON << ~asJson.(g)
~writeJSON.close

~readJSON = File(~jsonFile, "r")
~readJSON.readAllString

Please let me know if this works. I think it would be good if this function (of course array should be parsed correctly) was implemented as a method in the core library or quarks.

Maybe this helps

1 Like

Object.writeArchive and Object.readArchive are super easy. You just can’t expect to be able to human-read the file:

a = Array.fill(10, {[1.0.rand, 2.0.rand, 3.0.rand]});

a.writeArchive(Platform.defaultTempDir++"testArchive");

b = Object.readArchive(Platform.defaultTempDir++"testArchive");

b.postln;

Sam

Ah, cool, thanks folks!

I’m going to give the .asCompileString method a try since I don’t necessarily need to make the content human editable.