feat(file-system): async read/write (#7671)

This commit is contained in:
Peter Staev
2019-10-02 11:21:18 +03:00
committed by Manol Donev
parent 790870178c
commit 2146ac902f
14 changed files with 849 additions and 29 deletions

View File

@ -201,6 +201,46 @@ export var testFileReadWriteBinary = function () {
// << file-system-read-binary
};
export var testFileReadWriteBinaryAsync = function () {
// >> file-system-read-binary-async
var fileName = "logo.png";
var sourceFile = fs.File.fromPath(__dirname + "/assets/" + fileName);
var destinationFile = fs.knownFolders.documents().getFile(fileName);
// Read the file
sourceFile.read()
.then(function (source) {
// Succeeded in reading the file
// >> (hide)
destinationFile.write(source).then(function () {
// Succeded in writing the file
destinationFile.read()
.then(function (destination) {
if (platform.device.os === platform.platformNames.ios) {
TKUnit.assertTrue(source.isEqualToData(destination));
} else {
TKUnit.assertEqual(new java.io.File(sourceFile.path).length(), new java.io.File(destinationFile.path).length());
}
destinationFile.removeSync();
}, function (error) {
TKUnit.assert(false, "Failed to read destination binary async");
});
}, function (error) {
// Failed to write the file.
TKUnit.assert(false, "Failed to write binary async");
});
// << (hide)
}, function (error) {
// Failed to read the file.
// >> (hide)
TKUnit.assert(false, "Failed to read binary async");
// << (hide)
});
// << file-system-read-binary-async
};
export var testGetKnownFolders = function () {
// >> file-system-known-folders
// Getting the application's 'documents' folder.

View File

@ -11,15 +11,22 @@ import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@ -585,4 +592,278 @@ public class Async {
}
}
}
public static class File {
public static void readText(final String path, final String encoding, final CompleteCallback callback, final Object context) {
final android.os.Handler mHandler = new android.os.Handler();
threadPoolExecutor().execute(new Runnable() {
@Override
public void run() {
final ReadTextTask task = new ReadTextTask(callback, context);
final String result = task.doInBackground(path, encoding);
mHandler.post(new Runnable() {
@Override
public void run() {
task.onPostExecute(result);
}
});
}
});
}
public static void read(final String path, final CompleteCallback callback, final Object context) {
final android.os.Handler mHandler = new android.os.Handler();
threadPoolExecutor().execute(new Runnable() {
@Override
public void run() {
final ReadTask task = new ReadTask(callback, context);
final byte[] result = task.doInBackground(path);
mHandler.post(new Runnable() {
@Override
public void run() {
task.onPostExecute(result);
}
});
}
});
}
public static void writeText(final String path, final String content, final String encoding, final CompleteCallback callback, final Object context) {
final android.os.Handler mHandler = new android.os.Handler();
threadPoolExecutor().execute(new Runnable() {
@Override
public void run() {
final WriteTextTask task = new WriteTextTask(callback, context);
final boolean result = task.doInBackground(path, content, encoding);
mHandler.post(new Runnable() {
@Override
public void run() {
task.onPostExecute(result);
}
});
}
});
}
public static void write(final String path, final byte[] content, final CompleteCallback callback, final Object context) {
final android.os.Handler mHandler = new android.os.Handler();
threadPoolExecutor().execute(new Runnable() {
@Override
public void run() {
final WriteTask task = new WriteTask(callback, context);
final boolean result = task.doInBackground(path, content);
mHandler.post(new Runnable() {
@Override
public void run() {
task.onPostExecute(result);
}
});
}
});
}
static class ReadTextTask {
private CompleteCallback callback;
private Object context;
public ReadTextTask(CompleteCallback callback, Object context) {
this.callback = callback;
this.context = context;
}
protected String doInBackground(String... params) {
java.io.File javaFile = new java.io.File(params[0]);
FileInputStream stream = null;
try {
stream = new FileInputStream(javaFile);
InputStreamReader reader = new InputStreamReader(stream, params[1]);
CharBuffer buffer = CharBuffer.allocate(81920);
StringBuilder sb = new StringBuilder();
while (reader.read(buffer) != -1) {
buffer.flip();
sb.append(buffer);
buffer.clear();
}
reader.close();
return sb.toString();
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to read file, FileNotFoundException: " + e.getMessage());
return null;
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Failed to read file, UnsupportedEncodingException: " + e.getMessage());
return null;
} catch (IOException e) {
Log.e(TAG, "Failed to read file, IOException: " + e.getMessage());
return null;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close stream, IOException: " + e.getMessage());
}
}
}
}
protected void onPostExecute(final String result) {
if (result != null) {
this.callback.onComplete(result, this.context);
} else {
this.callback.onError("ReadTextTask returns no result.", this.context);
}
}
}
static class ReadTask {
private CompleteCallback callback;
private Object context;
public ReadTask(CompleteCallback callback, Object context) {
this.callback = callback;
this.context = context;
}
protected byte[] doInBackground(String... params) {
java.io.File javaFile = new java.io.File(params[0]);
FileInputStream stream = null;
try {
stream = new FileInputStream(javaFile);
byte[] result = new byte[(int)javaFile.length()];
DataInputStream dataInputStream = new DataInputStream(stream);
dataInputStream.readFully(result);
return result;
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to read file, FileNotFoundException: " + e.getMessage());
return null;
} catch (IOException e) {
Log.e(TAG, "Failed to read file, IOException: " + e.getMessage());
return null;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close stream, IOException: " + e.getMessage());
}
}
}
}
protected void onPostExecute(final byte[] result) {
if (result != null) {
this.callback.onComplete(result, this.context);
} else {
this.callback.onError("ReadTask returns no result.", this.context);
}
}
}
static class WriteTextTask {
private CompleteCallback callback;
private Object context;
public WriteTextTask(CompleteCallback callback, Object context) {
this.callback = callback;
this.context = context;
}
protected boolean doInBackground(String... params) {
java.io.File javaFile = new java.io.File(params[0]);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(javaFile);
OutputStreamWriter writer = new OutputStreamWriter(stream, params[2]);
writer.write(params[1]);
writer.close();
return true;
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to write file, FileNotFoundException: " + e.getMessage());
return false;
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Failed to write file, UnsupportedEncodingException: " + e.getMessage());
return false;
} catch (IOException e) {
Log.e(TAG, "Failed to write file, IOException: " + e.getMessage());
return false;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close stream, IOException: " + e.getMessage());
}
}
}
}
protected void onPostExecute(final boolean result) {
if (result) {
this.callback.onComplete(null, this.context);
} else {
this.callback.onError("WriteTextTask returns no result.", this.context);
}
}
}
static class WriteTask {
private CompleteCallback callback;
private Object context;
public WriteTask(CompleteCallback callback, Object context) {
this.callback = callback;
this.context = context;
}
protected boolean doInBackground(Object... params) {
java.io.File javaFile = new java.io.File((String)params[0]);
FileOutputStream stream = null;
byte[] content = (byte[])params[1];
try {
stream = new FileOutputStream(javaFile);
stream.write(content, 0, content.length);
return true;
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to write file, FileNotFoundException: " + e.getMessage());
return false;
} catch (IOException e) {
Log.e(TAG, "Failed to write file, IOException: " + e.getMessage());
return false;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close stream, IOException: " + e.getMessage());
}
}
}
}
protected void onPostExecute(final boolean result) {
if (result) {
this.callback.onComplete(null, this.context);
} else {
this.callback.onError("WriteTask returns no result.", this.context);
}
}
}
}
}

View File

@ -15,6 +15,10 @@
B8E76F5B212C2F4E009CFCE2 /* UIView+PropertyBag.m in Sources */ = {isa = PBXBuildFile; fileRef = B8E76F59212C2F4E009CFCE2 /* UIView+PropertyBag.m */; };
B8E76F5E212C3134009CFCE2 /* UIView+PassThroughParent.h in Headers */ = {isa = PBXBuildFile; fileRef = B8E76F5C212C3134009CFCE2 /* UIView+PassThroughParent.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8E76F5F212C3134009CFCE2 /* UIView+PassThroughParent.m in Sources */ = {isa = PBXBuildFile; fileRef = B8E76F5D212C3134009CFCE2 /* UIView+PassThroughParent.m */; };
D004030F22F781A50089EAD8 /* NSString+Async.h in Headers */ = {isa = PBXBuildFile; fileRef = D004030D22F781A50089EAD8 /* NSString+Async.h */; settings = {ATTRIBUTES = (Public, ); }; };
D004031022F781A50089EAD8 /* NSString+Async.m in Sources */ = {isa = PBXBuildFile; fileRef = D004030E22F781A50089EAD8 /* NSString+Async.m */; };
D004031322FA27D60089EAD8 /* NSData+Async.h in Headers */ = {isa = PBXBuildFile; fileRef = D004031122FA27D60089EAD8 /* NSData+Async.h */; settings = {ATTRIBUTES = (Public, ); }; };
D004031422FA27D60089EAD8 /* NSData+Async.m in Sources */ = {isa = PBXBuildFile; fileRef = D004031222FA27D60089EAD8 /* NSData+Async.m */; };
F915D3551EC9EF5E00071914 /* TNSProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = F915D3531EC9EF5E00071914 /* TNSProcess.m */; };
F915D3561EC9EF5E00071914 /* TNSProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = F915D3541EC9EF5E00071914 /* TNSProcess.h */; settings = {ATTRIBUTES = (Public, ); }; };
F98F5CB31CD0EFEA00978308 /* TNSWidgets.h in Headers */ = {isa = PBXBuildFile; fileRef = F98F5CB21CD0EFEA00978308 /* TNSWidgets.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -43,6 +47,10 @@
B8E76F59212C2F4E009CFCE2 /* UIView+PropertyBag.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+PropertyBag.m"; sourceTree = "<group>"; };
B8E76F5C212C3134009CFCE2 /* UIView+PassThroughParent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+PassThroughParent.h"; sourceTree = "<group>"; };
B8E76F5D212C3134009CFCE2 /* UIView+PassThroughParent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+PassThroughParent.m"; sourceTree = "<group>"; };
D004030D22F781A50089EAD8 /* NSString+Async.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+Async.h"; sourceTree = "<group>"; };
D004030E22F781A50089EAD8 /* NSString+Async.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+Async.m"; sourceTree = "<group>"; };
D004031122FA27D60089EAD8 /* NSData+Async.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+Async.h"; sourceTree = "<group>"; };
D004031222FA27D60089EAD8 /* NSData+Async.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+Async.m"; sourceTree = "<group>"; };
F915D3531EC9EF5E00071914 /* TNSProcess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TNSProcess.m; path = ../TNSProcess.m; sourceTree = "<group>"; };
F915D3541EC9EF5E00071914 /* TNSProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TNSProcess.h; path = ../TNSProcess.h; sourceTree = "<group>"; };
F98F5CAF1CD0EFEA00978308 /* TNSWidgets.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TNSWidgets.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -100,6 +108,8 @@
F98F5CB21CD0EFEA00978308 /* TNSWidgets.h */,
8B7321CD1D097ECD00884AC6 /* TNSLabel.h */,
8B7321CE1D097ECD00884AC6 /* TNSLabel.m */,
D004030D22F781A50089EAD8 /* NSString+Async.h */,
D004030E22F781A50089EAD8 /* NSString+Async.m */,
F98F5CC91CD0F09E00978308 /* UIImage+TNSBlocks.h */,
F98F5CCA1CD0F09E00978308 /* UIImage+TNSBlocks.m */,
F98F5CB41CD0EFEA00978308 /* Info.plist */,
@ -109,6 +119,8 @@
B8E76F59212C2F4E009CFCE2 /* UIView+PropertyBag.m */,
B8E76F5C212C3134009CFCE2 /* UIView+PassThroughParent.h */,
B8E76F5D212C3134009CFCE2 /* UIView+PassThroughParent.m */,
D004031122FA27D60089EAD8 /* NSData+Async.h */,
D004031222FA27D60089EAD8 /* NSData+Async.m */,
);
path = TNSWidgets;
sourceTree = "<group>";
@ -132,9 +144,11 @@
F915D3561EC9EF5E00071914 /* TNSProcess.h in Headers */,
F98F5CB31CD0EFEA00978308 /* TNSWidgets.h in Headers */,
B8E76F5E212C3134009CFCE2 /* UIView+PassThroughParent.h in Headers */,
D004031322FA27D60089EAD8 /* NSData+Async.h in Headers */,
F98F5CCB1CD0F09E00978308 /* UIImage+TNSBlocks.h in Headers */,
B8E76F52212C2DA2009CFCE2 /* NSObject+Swizzling.h in Headers */,
B8E76F5A212C2F4E009CFCE2 /* UIView+PropertyBag.h in Headers */,
D004030F22F781A50089EAD8 /* NSString+Async.h in Headers */,
8B7321CF1D097ECD00884AC6 /* TNSLabel.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -200,6 +214,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = F98F5CA51CD0EFEA00978308;
@ -239,6 +254,8 @@
F915D3551EC9EF5E00071914 /* TNSProcess.m in Sources */,
F98F5CCC1CD0F09E00978308 /* UIImage+TNSBlocks.m in Sources */,
B8E76F53212C2DA2009CFCE2 /* NSObject+Swizzling.m in Sources */,
D004031022F781A50089EAD8 /* NSString+Async.m in Sources */,
D004031422FA27D60089EAD8 /* NSData+Async.m in Sources */,
B8E76F5B212C2F4E009CFCE2 /* UIView+PropertyBag.m in Sources */,
B8E76F5F212C3134009CFCE2 /* UIView+PassThroughParent.m in Sources */,
);

View File

@ -0,0 +1,24 @@
//
// NSData+Async.h
// TNSWidgets
//
// Created by Peter Staev on 7.08.19.
// Copyright © 2019 Telerik A D. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSData (Async)
+ (void)dataWithContentsOfFile:(nonnull NSString*)path
completion:(void (^) (NSData*))callback;
- (void)writeToFile:(nonnull NSString*) path
atomically:(BOOL)atomically
completion:(void (^) ())callback;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,42 @@
//
// NSData+Async.m
// TNSWidgets
//
// Created by Peter Staev on 7.08.19.
// Copyright © 2019 Telerik A D. All rights reserved.
//
#import "NSData+Async.h"
@implementation NSData (Async)
+ (void)dataWithContentsOfFile:(nonnull NSString*)path
completion:(void (^) (NSData*))callback {
dispatch_queue_t asyncQueue = dispatch_queue_create("org.nativescript.TNSWidgets.data", NULL);
dispatch_async(asyncQueue, ^(void) {
NSData *output = [NSData dataWithContentsOfFile:path];
dispatch_async(dispatch_get_main_queue(), ^(void) {
callback(output);
});
});
}
- (void)writeToFile:(nonnull NSString*) path
atomically:(BOOL)atomically
completion:(void (^) ())callback {
dispatch_queue_t asyncQueue = dispatch_queue_create("org.nativescript.TNSWidgets.data", NULL);
dispatch_async(asyncQueue, ^(void) {
[self writeToFile:path
atomically:atomically];
dispatch_async(dispatch_get_main_queue(), ^(void) {
callback();
});
});
}
@end

View File

@ -0,0 +1,25 @@
//
// NSString+Async.h
// TNSWidgets
//
// Created by Peter Staev on 5.08.19.
// Copyright © 2019 Telerik A D. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (Async)
+ (void)stringWithContentsOfFile:(nonnull NSString*)path
encoding:(NSStringEncoding)enc
completion:(void (^) (NSString*, NSError*))callback;
- (void)writeToFile:(nonnull NSString*) path
atomically:(BOOL)atomically
encoding:(NSStringEncoding)enc
completion:(void (^) (NSError*))callback;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,50 @@
//
// NSString+Async.m
// TNSWidgets
//
// Created by Peter Staev on 5.08.19.
// Copyright © 2019 Telerik A D. All rights reserved.
//
#import "NSString+Async.h"
@implementation NSString (Async)
+ (void)stringWithContentsOfFile:(nonnull NSString*)path
encoding:(NSStringEncoding)enc
completion:(void (^) (NSString*, NSError*))callback {
dispatch_queue_t asyncQueue = dispatch_queue_create("org.nativescript.TNSWidgets.string", NULL);
dispatch_async(asyncQueue, ^(void) {
NSError *error = nil;
NSString *output = [NSString stringWithContentsOfFile:path
encoding:enc
error:&error];
dispatch_async(dispatch_get_main_queue(), ^(void) {
callback(output, error);
});
});
}
- (void)writeToFile:(nonnull NSString*)path
atomically:(BOOL)atomically
encoding:(NSStringEncoding)enc
completion:(void (^) (NSError*))callback {
dispatch_queue_t asyncQueue = dispatch_queue_create("org.nativescript.TNSWidgets.string", NULL);
dispatch_async(asyncQueue, ^(void) {
NSError *error = nil;
[self writeToFile:path
atomically:atomically
encoding:enc
error:&error];
dispatch_async(dispatch_get_main_queue(), ^(void) {
callback(error);
});
});
}
@end

View File

@ -20,3 +20,5 @@ FOUNDATION_EXPORT const unsigned char TNSWidgetsVersionString[];
#import "UIView+PassThroughParent.h"
#import "TNSLabel.h"
#import "TNSProcess.h"
#import "NSString+Async.h"
#import "NSData+Async.h"

View File

@ -218,7 +218,30 @@ export class FileSystemAccess {
return this.getLogicalRootPath() + "/app";
}
public read(path: string, onError?: (error: any) => any) {
public read = this.readSync.bind(this);
public readAsync(path: string): Promise<number[]> {
return new Promise<number[]>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.read(
path,
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: (result: number[]) => {
resolve(result);
},
onError: (err) => {
reject(new Error(err));
}
}),
null,
);
} catch (ex) {
reject(ex);
}
});
}
public readSync(path: string, onError?: (error: any) => any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileInputStream(javaFile);
@ -234,7 +257,31 @@ export class FileSystemAccess {
}
}
public write(path: string, bytes: native.Array<number>, onError?: (error: any) => any) {
public write = this.writeSync.bind(this);
public writeAsync(path: string, bytes: native.Array<number>): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.write(
path,
bytes,
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: () => {
resolve();
},
onError: (err) => {
reject(new Error(err));
}
}),
null,
);
} catch (ex) {
reject(ex);
}
});
}
public writeSync(path: string, bytes: native.Array<number>, onError?: (error: any) => any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileOutputStream(javaFile);
@ -247,7 +294,40 @@ export class FileSystemAccess {
}
}
public readText(path: string, onError?: (error: any) => any, encoding?: any) {
public readText = this.readTextSync.bind(this);
public readTextAsync(path: string, encoding?: any): Promise<string> {
let actualEncoding = encoding;
if (!actualEncoding) {
actualEncoding = textModule.encoding.UTF_8;
}
return new Promise<string>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.readText(
path,
actualEncoding,
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: (result: string) => {
if (actualEncoding === textModule.encoding.UTF_8) {
// Remove UTF8 BOM if present. http://www.rgagnon.com/javadetails/java-handle-utf8-file-with-bom.html
result = FileSystemAccess._removeUtf8Bom(result);
}
resolve(result);
},
onError: (err) => {
reject(new Error(err));
}
}),
null,
);
} catch (ex) {
reject(ex);
}
});
}
public readTextSync(path: string, onError?: (error: any) => any, encoding?: any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileInputStream(javaFile);
@ -302,7 +382,37 @@ export class FileSystemAccess {
return s;
}
public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
public writeText = this.writeTextSync.bind(this);
public writeTextAsync(path: string, content: string, encoding?: any): Promise<void> {
let actualEncoding = encoding;
if (!actualEncoding) {
actualEncoding = textModule.encoding.UTF_8;
}
return new Promise<void>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.writeText(
path,
content,
actualEncoding,
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: () => {
resolve();
},
onError: (err) => {
reject(new Error(err));
}
}),
null,
);
} catch (ex) {
reject(ex);
}
});
}
public writeTextSync(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileOutputStream(javaFile);

View File

@ -130,6 +130,23 @@ export class FileSystemAccess {
*/
readText(path: string, onError?: (error: any) => any, encoding?: any): string;
/**
* Reads a text from a file with a given path.
* @param path The path to the source file.
* @param encoding (optional) If set reads the text with the specified encoding (default UTF-8).
* Returns Promise of the text read.
*/
readTextAsync(path: string, encoding?: any): Promise<string>;
/**
* Reads a text from a file with a given path.
* @param path The path to the source file.
* @param onError (optional) A callback function to use if any error occurs.
* @param encoding (optional) If set reads the text with the specified encoding (default UTF-8).
* Returns the text read.
*/
readTextSync(path: string, onError?: (error: any) => any, encoding?: any): string;
/**
* Reads a binary content from a file with a given path.
* @param path The path to the source file.
@ -138,6 +155,21 @@ export class FileSystemAccess {
*/
read(path: string, onError?: (error: any) => any): any;
/**
* Reads a binary content from a file with a given path.
* @param path The path to the source file.
* Returns a Promise with the binary content read.
*/
readAsync(path: string): Promise<any>;
/**
* Reads a binary content from a file with a given path.
* @param path The path to the source file.
* @param onError (optional) A callback function to use if any error occurs.
* Returns the binary content read.
*/
readSync(path: string, onError?: (error: any) => any): any;
/**
* Writes a text to a file with a given path.
* @param path The path to the source file.
@ -147,6 +179,23 @@ export class FileSystemAccess {
*/
writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any);
/**
* Writes a text to a file with a given path.
* @param path The path to the source file.
* @param content The content which will be written to the file.
* @param encoding (optional) If set writes the text with the specified encoding (default UTF-8).
*/
writeTextAsync(path: string, content: string, encoding?: any): Promise<void>;
/**
* Writes a text to a file with a given path.
* @param path The path to the source file.
* @param content The content which will be written to the file.
* @param onError (optional) A callback function to use if any error occurs.
* @param encoding (optional) If set writes the text with the specified encoding (default UTF-8).
*/
writeTextSync(path: string, content: string, onError?: (error: any) => any, encoding?: any);
/**
* Writes a binary to a file with a given path.
* @param path The path to the source file.
@ -155,6 +204,21 @@ export class FileSystemAccess {
*/
write(path: string, content: any, onError?: (error: any) => any);
/**
* Writes a binary to a file with a given path.
* @param path The path to the source file.
* @param content The content which will be written to the file.
*/
writeAsync(path: string, content: any): Promise<void>;
/**
* Writes a binary to a file with a given path.
* @param path The path to the source file.
* @param content The content which will be written to the file.
* @param onError (optional) A callback function to use if any error occurs.
*/
writeSync(path: string, content: any, onError?: (error: any) => any);
/**
* Gets extension of the file with a given path.
* @param path A path to the file.

View File

@ -257,7 +257,31 @@ export class FileSystemAccess {
return ios.getCurrentAppPath();
}
public readText(path: string, onError?: (error: any) => any, encoding?: any) {
public readText = this.readTextSync.bind(this);
public readTextAsync(path: string, encoding?: any) {
const actualEncoding = encoding || textEncoding.UTF_8;
return new Promise<string>((resolve, reject) => {
try {
(NSString as any).stringWithContentsOfFileEncodingCompletion(
path,
actualEncoding,
(result, error) => {
if (error) {
reject(error);
} else {
resolve(result.toString());
}
},
);
} catch (ex) {
reject(new Error("Failed to read file at path '" + path + "': " + ex));
}
});
}
public readTextSync(path: string, onError?: (error: any) => any, encoding?: any) {
const actualEncoding = encoding || textEncoding.UTF_8;
try {
@ -271,7 +295,19 @@ export class FileSystemAccess {
}
}
public read(path: string, onError?: (error: any) => any): NSData {
public read = this.readSync.bind(this);
public readAsync(path: string): Promise<NSData> {
return new Promise<NSData>((resolve, reject) => {
try {
(NSData as any).dataWithContentsOfFileCompletion(path, resolve);
} catch (ex) {
reject(new Error("Failed to read file at path '" + path + "': " + ex));
}
});
}
public readSync(path: string, onError?: (error: any) => any): NSData {
try {
return NSData.dataWithContentsOfFile(path);
} catch (ex) {
@ -281,7 +317,33 @@ export class FileSystemAccess {
}
}
public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
public writeText = this.writeTextSync.bind(this);
public writeTextAsync(path: string, content: string, encoding?: any): Promise<void> {
const nsString = NSString.stringWithString(content);
const actualEncoding = encoding || textEncoding.UTF_8;
return new Promise<void>((resolve, reject) => {
try {
(nsString as any).writeToFileAtomicallyEncodingCompletion(
path,
true,
actualEncoding,
(error) => {
if (error) {
reject(error);
} else {
resolve();
}
},
);
} catch (ex) {
reject(new Error("Failed to write file at path '" + path + "': " + ex));
}
});
}
public writeTextSync(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
const nsString = NSString.stringWithString(content);
const actualEncoding = encoding || textEncoding.UTF_8;
@ -296,7 +358,23 @@ export class FileSystemAccess {
}
}
public write(path: string, content: NSData, onError?: (error: any) => any) {
public write = this.writeSync.bind(this);
public writeAsync(path: string, content: NSData): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
(content as any).writeToFileAtomicallyCompletion(
path,
true,
() => { resolve(); },
);
} catch (ex) {
reject(new Error("Failed to write file at path '" + path + "': " + ex));
}
});
}
public writeSync(path: string, content: NSData, onError?: (error: any) => any) {
try {
content.writeToFileAtomically(path, true);
} catch (ex) {

View File

@ -96,6 +96,11 @@ export class File extends FileSystemEntity {
*/
readTextSync(onError?: (error: any) => any, encoding?: string): string;
/**
* Reads the binary content of the file asynchronously.
*/
read(): Promise<any>;
/**
* Reads the binary content of the file synchronously.
* @param onError An optional function to be called if some IO-error occurs.
@ -117,6 +122,12 @@ export class File extends FileSystemEntity {
*/
writeTextSync(content: string, onError?: (error: any) => any, encoding?: string): void;
/**
* Writes the provided binary content to the file.
* @param content The binary content to be saved to the file.
*/
write(content: any): Promise<void>;
/**
* Writes the provided binary content to the file synchronously.
* @param content The binary content to be saved to the file.

View File

@ -207,6 +207,31 @@ export class File extends FileSystemEntity {
return getFileAccess().getFileSize(this.path);
}
public read(): Promise<any> {
return new Promise<any>((resolve, reject) => {
try {
this.checkAccess();
} catch (ex) {
reject(ex);
return;
}
this._locked = true;
getFileAccess().readAsync(this.path).then(
(result) => {
resolve(result);
this._locked = false;
},
(error) => {
reject(error);
this._locked = false;
},
);
});
}
public readSync(onError?: (error: any) => any): any {
this.checkAccess();
@ -220,7 +245,7 @@ export class File extends FileSystemEntity {
}
};
const content = getFileAccess().read(this.path, localError);
const content = getFileAccess().readSync(this.path, localError);
this._locked = false;
@ -228,6 +253,31 @@ export class File extends FileSystemEntity {
}
public write(content: any): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
this.checkAccess();
} catch (ex) {
reject(ex);
return;
}
this._locked = true;
getFileAccess().writeAsync(this.path, content).then(
() => {
resolve();
this._locked = false;
},
(error) => {
reject(error);
this._locked = false;
},
);
});
}
public writeSync(content: any, onError?: (error: any) => any): void {
this.checkAccess();
@ -242,7 +292,7 @@ export class File extends FileSystemEntity {
}
};
getFileAccess().write(this.path, content, localError);
getFileAccess().writeSync(this.path, content, localError);
} finally {
this._locked = false;
}
@ -250,16 +300,26 @@ export class File extends FileSystemEntity {
public readText(encoding?: string): Promise<string> {
return new Promise((resolve, reject) => {
let hasError = false;
const localError = (error) => {
hasError = true;
reject(error);
};
try {
this.checkAccess();
} catch (ex) {
reject(ex);
const content = this.readTextSync(localError, encoding);
if (!hasError) {
resolve(content);
return;
}
this._locked = true;
getFileAccess().readTextAsync(this.path, encoding).then(
(result) => {
resolve(result);
this._locked = false;
},
(error) => {
reject(error);
this._locked = false;
},
);
});
}
@ -277,7 +337,7 @@ export class File extends FileSystemEntity {
}
};
const content = getFileAccess().readText(this.path, localError, encoding);
const content = getFileAccess().readTextSync(this.path, localError, encoding);
this._locked = false;
return content;
@ -285,16 +345,26 @@ export class File extends FileSystemEntity {
public writeText(content: string, encoding?: string): Promise<any> {
return new Promise((resolve, reject) => {
let hasError = false;
const localError = function (error) {
hasError = true;
reject(error);
};
try {
this.checkAccess();
} catch (ex) {
reject(ex);
this.writeTextSync(content, localError, encoding);
if (!hasError) {
resolve();
return;
}
this._locked = true;
getFileAccess().writeTextAsync(this.path, content, encoding).then(
() => {
resolve();
this._locked = false;
},
(error) => {
reject(error);
this._locked = false;
},
);
});
}
@ -312,8 +382,7 @@ export class File extends FileSystemEntity {
}
};
// TODO: Asyncronous
getFileAccess().writeText(this.path, content, localError, encoding);
getFileAccess().writeTextSync(this.path, content, localError, encoding);
} finally {
this._locked = false;
}

View File

@ -17,6 +17,13 @@
export function download(url: string, callback: CompleteCallback, context: any);
}
export module File {
export function readText(path: string, encoding: string, callback: CompleteCallback, context: any);
export function read(path: string, callback: CompleteCallback, context: any);
export function writeText(path: string, content: string, encoding: string, callback: CompleteCallback, context: any);
export function write(path: string, content: native.Array<number>, callback: CompleteCallback, context: any);
}
export module Http {
export class KeyValuePair {
public key: string;