diff --git a/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets b/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets index 67eb95add30a0cd803f0542ae46c90f870189651..6529112623937ce75daa8815bee24eec4c8d346f 100644 --- a/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets +++ b/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets @@ -13,6 +13,7 @@ * limitations under the License. */ import { BusinessError, AsyncCallback } from '@ohos.base'; +import stream from '@ohos.util.stream'; function access(path: string, mode?: AccessModeType): Promise { return new Promise((resolve: (result: boolean) => void, reject: (e: BusinessError) => void) => { @@ -492,6 +493,14 @@ function stat(file: string | number, callback: AsyncCallback): void }); } +function createReadStream(path: string, options?: ReadStreamOptions): ReadStream { + return new ReadStream(path, options) +} + +function createWriteStream(path: string, options?: WriteStreamOptions): WriteStream { + return new WriteStream(path, options); +} + export interface Filter { suffix?: Array; displayName?: Array; @@ -623,6 +632,195 @@ class StatInner implements Stat { native isSymbolicLink(): boolean; } +enum OpenMode { + READ_ONLY = 0o0, + WRITE_ONLY = 0o1, + READ_WRITE = 0o2, + CREATE = 0o100, + TRUNC = 0o1000, + APPEND = 0o2000, + NONBLOCK = 0o4000, + DIR = 0o200000, + NOFOLLOW = 0o400000, + SYNC = 0o4010000, +} + +enum WhenceType { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2, +} + +export interface ReadStreamOptions { + start?: number; + end?: number; +} + +export interface WriteStreamOptions { + mode?: number; + start?: number; +} + +export class ReadStream extends stream.Readable { + private pathInner: string; + private bytesReadInner: number; + private offset: number; + private start?: number; + private end?: number; + private stream?: Stream; + + constructor(path: string, options?: ReadStreamOptions) { + super(); + this.pathInner = path; + this.bytesReadInner = 0; + this.start = options?.start; + this.end = options?.end; + this.stream = createStreamSync(this.pathInner, 'r'); + this.offset = this.start ?? 0; + } + + get path(): string { + return this.pathInner; + } + + get bytesRead(): number { + return this.bytesReadInner; + } + + seek(offset: number, whence?: WhenceType): number { + if (whence === undefined) { + let off = this.stream?.seek(offset); + if (off !== undefined) { + this.offset = off + } + } else { + let off = this.stream?.seek(offset, whence); + if (off !== undefined) { + this.offset = off + } + } + return this.offset; + } + + close(): void { + this.stream?.close(); + } + + doInitialize(callback: () => void): void { + callback(); + } + + doRead(size: number): void { + let readSize = size; + let end = this.end + if (end !== undefined) { + if (this.offset > end) { + this.push(null); + return; + } + if (this.offset + readSize > end) { + readSize = end - this.offset; + } + } + let buffer = new ArrayBuffer(readSize); + const off = this.offset; + this.offset += readSize; + this.stream?.read(buffer, { offset: off, length: readSize }) + .then((readOut: number) => { + if (readOut > 0) { + this.bytesReadInner += readOut; + this.push(new Uint8Array(buffer.slice(0, readOut))); + } + if (readOut !== readSize || readOut < size) { + this.offset = this.offset - readSize + readOut; + this.push(null); + } + }); + } +} + +export class WriteStream extends stream.Writable { + private pathInner: string; + private bytesWrittenInner: number; + private offset: number; + private mode: string; + private start?: number; + private stream?: Stream; + + constructor(path: string, options?: WriteStreamOptions) { + super(); + this.pathInner = path; + this.bytesWrittenInner = 0; + this.start = options?.start; + this.mode = this.convertOpenMode(options?.mode); + this.stream = createStreamSync(this.pathInner, this.mode); + this.offset = this.start ?? 0; + } + + get path(): string { + return this.pathInner; + } + + get bytesWritten(): number { + return this.bytesWrittenInner; + } + + seek(offset: number, whence?: WhenceType): number { + if (whence === undefined) { + let off = this.stream?.seek(offset); + if (off !== undefined) { + this.offset = off + } + } else { + let off = this.stream?.seek(offset, whence); + if (off !== undefined) { + this.offset = off + } + } + return this.offset; + } + + close(): void { + this.stream?.close(); + } + + doInitialize(callback: () => void): void { + callback(); + } + + doWrite(chunk: string | ArrayBuffer, encoding: string, callback: () => void): void { + this.stream?.write(chunk, { offset: this.offset }) + .then((writeIn: number) => { + this.offset += writeIn; + this.bytesWrittenInner += writeIn; + callback(); + }) + .finally(() => { + this.stream?.flush(); + }); + } + + convertOpenMode(mode?: number): string { + let modeStr = 'w'; + if (mode === undefined) { + return modeStr; + } + if ((mode as number) & OpenMode.WRITE_ONLY) { + modeStr = 'w'; + } + if ((mode as number) & OpenMode.READ_WRITE) { + modeStr = 'w+'; + } + if (((mode as number) & OpenMode.WRITE_ONLY) && ((mode as number) & OpenMode.APPEND)) { + modeStr = 'a'; + } + if (((mode as number) & OpenMode.READ_WRITE) && ((mode as number) & OpenMode.APPEND)) { + modeStr = 'a+'; + } + return modeStr; + } +} + class FileIoImpl { static {