diff --git a/apps/tests/file-system-tests.ts b/apps/tests/file-system-tests.ts index 5a0a64ae4..daf97d56c 100644 --- a/apps/tests/file-system-tests.ts +++ b/apps/tests/file-system-tests.ts @@ -224,6 +224,24 @@ export var testFileRead = function () { // }; +export var testFileReadWriteBinary = function () { + // + // ### Reading/writing binary data from/to a File + // ``` JavaScript + var fileName = "logo.png"; + + var sourceFile = fs.knownFolders.currentApp().getFile(fileName); + var destinationFile = fs.knownFolders.temp().getFile(fileName); + + destinationFile.writeSync(sourceFile.readSync()); + + TKUnit.assertEqual(sourceFile.readSync(), destinationFile.readSync()); + + destinationFile.removeSync(); + // ``` + // +}; + export var testGetKnownFolders = function () { // // ### Getting the Known Folders diff --git a/file-system/file-system-access.android.ts b/file-system/file-system-access.android.ts index 383553d99..9b5bdae34 100644 --- a/file-system/file-system-access.android.ts +++ b/file-system/file-system-access.android.ts @@ -192,6 +192,35 @@ export class FileSystemAccess { return dir.getAbsolutePath(); } + public read(path: string, onError?: (error: any) => any) { + try { + var javaFile = new java.io.File(path); + var stream = new java.io.FileInputStream(javaFile); + var bytes = new byte[javaFile.length()]; + var dataInputStream = new java.io.DataInputStream(stream); + dataInputStream.readFully(bytes); + return bytes; + } catch (exception) { + if (onError) { + onError(exception); + } + } + } + + public write(path: string, content: java.io.ByteArrayOutputStream, onError?: (error: any) => any) { + try { + var javaFile = new java.io.File(path); + var stream = new java.io.FileOutputStream(javaFile); + var bytes = content.toByteArray(); + stream.write(bytes, 0, bytes.length); + stream.close(); + } catch (exception) { + if (onError) { + onError(exception); + } + } + } + public readText(path: string, onError?: (error: any) => any, encoding?: any) { try { var types: typeof typesModule = require("utils/types"); diff --git a/file-system/file-system-access.d.ts b/file-system/file-system-access.d.ts index aa0ddfec4..891fbeee6 100644 --- a/file-system/file-system-access.d.ts +++ b/file-system/file-system-access.d.ts @@ -108,6 +108,14 @@ */ readText(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. + * @param onSuccess A callback function which is called when a text is red. + * @param onError (optional) A callback function to use if any error occurs. + */ + read(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. @@ -118,6 +126,15 @@ */ writeText(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. + * @param content The content which will be written to the file. + * @param onSuccess (optional) A callback function which is called when a text is written. + * @param onError (optional) A callback function to use if any error occurs. + */ + write(path: string, content: any, onError?: (error: any) => any); + /** * Gets extension of the file with a given path. * @param path A path to the file. diff --git a/file-system/file-system-access.ios.ts b/file-system/file-system-access.ios.ts index 4e8bfd049..d0aae5436 100644 --- a/file-system/file-system-access.ios.ts +++ b/file-system/file-system-access.ios.ts @@ -239,6 +239,17 @@ export class FileSystemAccess { } } + public read(path: string, onError?: (error: any) => any) : NSData { + try { + return NSData.dataWithContentsOfFile(path); + } + catch (ex) { + if (onError) { + onError(new Error("Failed to read file at path '" + path + "': " + ex)); + } + } + } + public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) { var nsString = NSString.alloc().initWithString(content); @@ -258,6 +269,17 @@ export class FileSystemAccess { } } + public write(path: string, content: NSData, onError?: (error: any) => any) { + try { + content.writeToFileAtomically(path, true); + } + catch (ex) { + if (onError) { + onError(new Error("Failed to write to file '" + path + "': " + ex)); + } + } + } + private getKnownPath(folderType: number): string { var fileManager = NSFileManager.defaultManager(); var paths = fileManager.URLsForDirectoryInDomains(folderType, this.userDomain); diff --git a/file-system/file-system.d.ts b/file-system/file-system.d.ts index 579cecd69..8b1169b1e 100644 --- a/file-system/file-system.d.ts +++ b/file-system/file-system.d.ts @@ -3,9 +3,9 @@ */ declare module "file-system" { - /** - * Represents a single entity on the file system. - */ + /** + * Represents a single entity on the file system. + */ export class FileSystemEntity { /** * Gets the Date object specifying the last time this entity was modified. @@ -52,9 +52,9 @@ declare module "file-system" { renameSync(newName: string, onError?: (error: any) => any): void; } - /** - * Represents a File entity on the file system. - */ + /** + * Represents a File entity on the file system. + */ export class File extends FileSystemEntity { /** * Checks whether a File with the specified path already exists. @@ -91,6 +91,12 @@ declare module "file-system" { */ readTextSync(onError?: (error: any) => any, encoding?: string): string; + /** + * Reads the binary content of the file synchronously. + * @param onError An optional function to be called if some IO-error occurs. + */ + readSync(onError?: (error: any) => any): any; + /** * Writes the provided string to the file, using the specified encoding (defaults to UTF-8). * @param content The content to be saved to the file. @@ -105,6 +111,13 @@ declare module "file-system" { * @param encoding An optional value specifying the preferred encoding (defaults to UTF-8). */ writeTextSync(content: string, onError?: (error: any) => any, encoding?: string): void; + + /** + * Writes the provided binary content to the file synchronously. + * @param content The binary content to be saved to the file. + * @param onError An optional function to be called if some IO-error occurs. + */ + writeSync(content: any, onError?: (error: any) => any): void; } /** @@ -176,46 +189,46 @@ declare module "file-system" { eachEntity(onEntity: (entity: FileSystemEntity) => boolean); } - /** - * Provides access to the top-level Folders instances that are accessible from the application. Use these as entry points to access the FileSystem. - */ + /** + * Provides access to the top-level Folders instances that are accessible from the application. Use these as entry points to access the FileSystem. + */ module knownFolders { - /** - * Gets the Documents folder available for the current application. This Folder is private for the application and not accessible from Users/External apps. - */ + /** + * Gets the Documents folder available for the current application. This Folder is private for the application and not accessible from Users/External apps. + */ export function documents(): Folder; - /** - * Gets the Temporary (Caches) folder available for the current application. This Folder is private for the application and not accessible from Users/External apps. - */ + /** + * Gets the Temporary (Caches) folder available for the current application. This Folder is private for the application and not accessible from Users/External apps. + */ export function temp(): Folder; - /** - * Gets the root folder for the current application. This Folder is private for the application and not accessible from Users/External apps. - * iOS - this folder is read-only and contains the app and all its resources. - */ + /** + * Gets the root folder for the current application. This Folder is private for the application and not accessible from Users/External apps. + * iOS - this folder is read-only and contains the app and all its resources. + */ export function currentApp(): Folder; } - /** - * Enables path-specific operations like join, extension, etc. - */ + /** + * Enables path-specific operations like join, extension, etc. + */ export module path { - /** - * Normalizes a path, taking care of occurrances like ".." and "//". - * @param path The path to be normalized. - */ + /** + * Normalizes a path, taking care of occurrances like ".." and "//". + * @param path The path to be normalized. + */ export function normalize(path: string): string; - /** - * Joins all the provided string components, forming a valid and normalized path. - * @param paths An array of string components to be joined. - */ + /** + * Joins all the provided string components, forming a valid and normalized path. + * @param paths An array of string components to be joined. + */ export function join(...paths: string[]): string; - /** - * Gets the string used to separate file paths. - */ + /** + * Gets the string used to separate file paths. + */ export var separator: string; } } \ No newline at end of file diff --git a/file-system/file-system.ts b/file-system/file-system.ts index f1f27fb60..bc91805b4 100644 --- a/file-system/file-system.ts +++ b/file-system/file-system.ts @@ -193,6 +193,47 @@ export class File extends FileSystemEntity { return !!this[fileLockedProperty]; } + public readSync(onError?: (error: any) => any): any { + this.checkAccess(); + + this[fileLockedProperty] = true; + + var that = this; + var localError = (error) => { + that[fileLockedProperty] = false; + if (onError) { + onError(error); + } + }; + + var content = getFileAccess().read(this.path, localError); + + this[fileLockedProperty] = false; + + return content; + + } + + public writeSync(content: any, onError?: (error: any) => any): void { + this.checkAccess(); + + try { + this[fileLockedProperty] = true; + + var that = this; + var localError = function (error) { + that[fileLockedProperty] = false; + if (onError) { + onError(error); + } + }; + + getFileAccess().write(this.path, content, localError); + } finally { + this[fileLockedProperty] = false; + } + } + public readText(encoding?: string): Promise { return new Promise((resolve, reject) => { var hasError = false;