Additional file read/write functions

This commit is contained in:
EliteMasterEric 2023-06-08 16:42:02 -04:00
parent f5046cece6
commit 657d898090

View file

@ -18,7 +18,7 @@ class FileUtil
/**
* Browses for a single file, then calls `onSelect(path)` when a path chosen.
* Note that on HTML5 this will immediately fail, you should call `openFile(onOpen:Resource->Void)` instead.
*
*
* @param typeFilter Filters what kinds of files can be selected.
* @return Whether the file dialog was opened successfully.
*/
@ -26,9 +26,9 @@ class FileUtil
?dialogTitle:String):Bool
{
#if desktop
var filter = convertTypeFilter(typeFilter);
var filter:String = convertTypeFilter(typeFilter);
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSelect != null) fileDialog.onSelect.add(onSelect);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
@ -46,7 +46,7 @@ class FileUtil
/**
* Browses for a directory, then calls `onSelect(path)` when a path chosen.
* Note that on HTML5 this will immediately fail.
*
*
* @param typeFilter TODO What does this do?
* @return Whether the file dialog was opened successfully.
*/
@ -54,9 +54,9 @@ class FileUtil
?dialogTitle:String):Bool
{
#if desktop
var filter = convertTypeFilter(typeFilter);
var filter:String = convertTypeFilter(typeFilter);
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSelect != null) fileDialog.onSelect.add(onSelect);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
@ -74,16 +74,16 @@ class FileUtil
/**
* Browses for multiple file, then calls `onSelect(paths)` when a path chosen.
* Note that on HTML5 this will immediately fail.
*
*
* @return Whether the file dialog was opened successfully.
*/
public static function browseForMultipleFiles(?typeFilter:Array<FileFilter>, ?onSelect:Array<String>->Void, ?onCancel:Void->Void, ?defaultPath:String,
?dialogTitle:String):Bool
{
#if desktop
var filter = convertTypeFilter(typeFilter);
var filter:String = convertTypeFilter(typeFilter);
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSelect != null) fileDialog.onSelectMultiple.add(onSelect);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
@ -101,7 +101,7 @@ class FileUtil
/**
* Browses for a file location to save to, then calls `onSelect(path)` when a path chosen.
* Note that on HTML5 you can't do much with this, you should call `saveFile(resource:haxe.io.Bytes)` instead.
*
*
* @param typeFilter TODO What does this do?
* @return Whether the file dialog was opened successfully.
*/
@ -109,9 +109,9 @@ class FileUtil
?dialogTitle:String):Bool
{
#if desktop
var filter = convertTypeFilter(typeFilter);
var filter:String = convertTypeFilter(typeFilter);
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSelect != null) fileDialog.onSelect.add(onSelect);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
@ -129,36 +129,36 @@ class FileUtil
/**
* Browses for a single file location, then reads it and passes it to `onOpen(resource:haxe.io.Bytes)`.
* Works great on desktop and HTML5.
*
*
* @param typeFilter TODO What does this do?
* @return Whether the file dialog was opened successfully.
*/
public static function openFile(?typeFilter:Array<FileFilter>, ?onOpen:Bytes->Void, ?onCancel:Void->Void, ?defaultPath:String, ?dialogTitle:String):Bool
{
#if desktop
var filter = convertTypeFilter(typeFilter);
var filter:String = convertTypeFilter(typeFilter);
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onOpen != null) fileDialog.onOpen.add(onOpen);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
fileDialog.open(filter, defaultPath, dialogTitle);
return true;
#elseif html5
var onFileLoaded = function(event) {
var onFileLoaded:Event->Void = function(event) {
var loadedFileRef:FileReference = event.target;
trace('Loaded file: ' + loadedFileRef.name);
onOpen(loadedFileRef.data);
}
var onFileSelected = function(event) {
var onFileSelected:Event->Void = function(event) {
var selectedFileRef:FileReference = event.target;
trace('Selected file: ' + selectedFileRef.name);
selectedFileRef.addEventListener(Event.COMPLETE, onFileLoaded);
selectedFileRef.load();
}
var fileRef = new FileReference();
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.SELECT, onFileSelected);
fileRef.browse(typeFilter);
return true;
@ -171,24 +171,24 @@ class FileUtil
/**
* Browses for a single file location, then writes the provided `haxe.io.Bytes` data and calls `onSave(path)` when done.
* Works great on desktop and HTML5.
*
*
* @return Whether the file dialog was opened successfully.
*/
public static function saveFile(data:Bytes, ?onSave:String->Void, ?onCancel:Void->Void, ?defaultFileName:String, ?dialogTitle:String):Bool
{
#if desktop
var filter = defaultFileName != null ? Path.extension(defaultFileName) : null;
var filter:String = defaultFileName != null ? Path.extension(defaultFileName) : null;
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSave != null) fileDialog.onSelect.add(onSave);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
fileDialog.save(data, filter, defaultFileName, dialogTitle);
return true;
#elseif html5
var filter = defaultFileName != null ? Path.extension(defaultFileName) : null;
var filter:String = defaultFileName != null ? Path.extension(defaultFileName) : null;
var fileDialog = new FileDialog();
var fileDialog:FileDialog = new FileDialog();
if (onSave != null) fileDialog.onSave.add(onSave);
if (onCancel != null) fileDialog.onCancel.add(onCancel);
@ -204,7 +204,7 @@ class FileUtil
* Prompts the user to save multiple files.
* On desktop, this will prompt the user for a directory, then write all of the files to there.
* On HTML5, this will zip the files up and prompt the user to save that.
*
*
* @param typeFilter TODO What does this do?
* @return Whether the file dialog was opened successfully.
*/
@ -213,7 +213,7 @@ class FileUtil
{
#if desktop
// Prompt the user for a directory, then write all of the files to there.
var onSelectDir = function(targetPath:String) {
var onSelectDir:String->Void = function(targetPath:String):Void {
var paths:Array<String> = [];
for (resource in resources)
{
@ -230,7 +230,7 @@ class FileUtil
writeBytesToPath(filePath, resource.data, force ? Force : Skip);
}
}
catch (e:Dynamic)
catch (_)
{
trace('Failed to write file (probably already exists): $filePath' + filePath);
continue;
@ -240,7 +240,7 @@ class FileUtil
onSaveAll(paths);
}
browseForDirectory(null, onSelectDir, onCancel, defaultPath, "Choose directory to save all files to...");
browseForDirectory(null, onSelectDir, onCancel, defaultPath, 'Choose directory to save all files to...');
return true;
#elseif html5
@ -260,14 +260,14 @@ class FileUtil
?force:Bool = false):Bool
{
// Create a ZIP file.
var zipBytes = createZIPFromEntries(resources);
var zipBytes:Bytes = createZIPFromEntries(resources);
var onSave = function(path:String) {
var onSave:String->Void = function(path:String) {
onSave([path]);
};
// Prompt the user to save the ZIP file.
saveFile(zipBytes, onSave, onCancel, defaultPath, "Save files as ZIP...");
saveFile(zipBytes, onSave, onCancel, defaultPath, 'Save files as ZIP...');
return true;
}
@ -282,7 +282,7 @@ class FileUtil
{
#if desktop
// Create a ZIP file.
var zipBytes = createZIPFromEntries(resources);
var zipBytes:Bytes = createZIPFromEntries(resources);
// Write the ZIP.
writeBytesToPath(path, zipBytes, force ? Force : Skip);
@ -293,13 +293,70 @@ class FileUtil
#end
}
/**
* Read string file contents directly from a given path.
* Only works on desktop.
*
* @param path The path to the file.
* @return The file contents.
*/
public static function readStringFromPath(path:String):String
{
#if sys
return sys.io.File.getContent(path);
#else
return null;
#end
}
/**
* Read bytes file contents directly from a given path.
* Only works on desktop.
*
* @param path The path to the file.
* @return The file contents.
*/
public static function readBytesFromPath(path:String):Bytes
{
#if sys
return Bytes.ofString(sys.io.File.getContent(path));
#else
return null;
#end
}
/**
* Read JSON file contents directly from a given path.
* Only works on desktop.
*
* @param path The path to the file.
* @return The JSON data.
*/
public static function readJSONFromPath(path:String):Dynamic
{
#if sys
try
{
return SerializerUtil.fromJSON(sys.io.File.getContent(path));
}
catch (ex)
{
return null;
}
#else
return null;
#end
}
/**
* Write string file contents directly to a given path.
* Only works on desktop.
*
*
* @param path The path to the file.
* @param data The string to write.
* @param mode Whether to Force, Skip, or Ask to overwrite an existing file.
*/
public static function writeStringToPath(path:String, data:String, mode:FileWriteMode = Skip)
public static function writeStringToPath(path:String, data:String, mode:FileWriteMode = Skip):Void
{
#if sys
createDirIfNotExists(Path.directory(path));
@ -335,10 +392,12 @@ class FileUtil
/**
* Write byte file contents directly to a given path.
* Only works on desktop.
*
*
* @param path The path to the file.
* @param data The bytes to write.
* @param mode Whether to Force, Skip, or Ask to overwrite an existing file.
*/
public static function writeBytesToPath(path:String, data:Bytes, mode:FileWriteMode = Skip)
public static function writeBytesToPath(path:String, data:Bytes, mode:FileWriteMode = Skip):Void
{
#if sys
createDirIfNotExists(Path.directory(path));
@ -374,8 +433,11 @@ class FileUtil
/**
* Write string file contents directly to the end of a file at the given path.
* Only works on desktop.
*
* @param path The path to the file.
* @param data The string to append.
*/
public static function appendStringToPath(path:String, data:String)
public static function appendStringToPath(path:String, data:String):Void
{
#if sys
sys.io.File.append(path, false).writeString(data);
@ -387,8 +449,10 @@ class FileUtil
/**
* Create a directory if it doesn't already exist.
* Only works on desktop.
*
* @param dir The path to the directory.
*/
public static function createDirIfNotExists(dir:String)
public static function createDirIfNotExists(dir:String):Void
{
#if sys
if (!sys.FileSystem.exists(dir))
@ -404,6 +468,8 @@ class FileUtil
/**
* Get the path to a temporary directory we can use for writing files.
* Only works on desktop.
*
* @return The path to the temporary directory.
*/
public static function getTempDir():String
{
@ -421,9 +487,11 @@ class FileUtil
if (path != null) break;
}
return tempDir = Path.join([path, 'funkin/']);
tempDir = Path.join([path, 'funkin/']);
return tempDir;
#else
return tempDir = '/tmp/funkin/';
tempDir = '/tmp/funkin/';
return tempDir;
#end
#else
return null;
@ -432,15 +500,15 @@ class FileUtil
/**
* Create a Bytes object containing a ZIP file, containing the provided entries.
*
*
* @param entries The entries to add to the ZIP file.
* @return The ZIP file as a Bytes object.
*/
public static function createZIPFromEntries(entries:Array<Entry>):Bytes
{
var o = new haxe.io.BytesOutput();
var o:haxe.io.BytesOutput = new haxe.io.BytesOutput();
var zipWriter = new haxe.zip.Writer(o);
var zipWriter:haxe.zip.Writer = new haxe.zip.Writer(o);
zipWriter.write(entries.list());
return o.getBytes();
@ -448,15 +516,27 @@ class FileUtil
/**
* Create a ZIP file entry from a file name and its string contents.
*
*
* @param name The name of the file. You can use slashes to create subdirectories.
* @param content The string contents of the file.
* @return The resulting entry.
*/
public static function makeZIPEntry(name:String, content:String):Entry
{
var data = haxe.io.Bytes.ofString(content, UTF8);
var data:Bytes = haxe.io.Bytes.ofString(content, UTF8);
return makeZIPEntryFromBytes(name, data);
}
/**
* Create a ZIP file entry from a file name and its string contents.
*
* @param name The name of the file. You can use slashes to create subdirectories.
* @param data The byte data of the file.
* @return The resulting entry.
*/
public static function makeZIPEntryFromBytes(name:String, data:haxe.io.Bytes):Entry
{
return {
fileName: name,
fileSize: data.length,
@ -474,15 +554,15 @@ class FileUtil
static function convertTypeFilter(typeFilter:Array<FileFilter>):String
{
var filter = null;
var filter:String = null;
if (typeFilter != null)
{
var filters = [];
var filters:Array<String> = [];
for (type in typeFilter)
{
filters.push(StringTools.replace(StringTools.replace(type.extension, "*.", ""), ";", ","));
filters.push(StringTools.replace(StringTools.replace(type.extension, '*.', ''), ';', ','));
}
filter = filters.join(";");
filter = filters.join(';');
}
return filter;