Last active
August 29, 2015 14:05
-
-
Save zenparsing/26b200543bb8ae0ca4df to your computer and use it in GitHub Desktop.
Reading and Writing Files with Async Generators
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This example uses an inner generator and skips over the first iteration in order to | |
prevent data loss which occurs on the first call to next. | |
*/ | |
import * as FS from "async-fs"; | |
export function readFile(path) { | |
async function* inner() { | |
let fd = await FS.open(path, "r"), | |
position = 0, | |
bytesRead, | |
buffer; | |
try { | |
// Send filled buffer view to consumer and wait until consumer has called | |
// `next` with a buffer to fill. | |
while (buffer = await yield buffer) { | |
// Stop if past EOF | |
if (bytesRead === 0) | |
break; | |
bytesRead = await FS.read(fd, buffer, buffer.length, position); | |
position += bytesRead; | |
buffer = buffer.slice(0, written); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
} | |
// Skip past the first iteration in order to prevent data loss | |
var iter = inner(); | |
iter.next(); | |
return iter; | |
} | |
export function writeFile(path) { | |
async function* inner() { | |
let fd = await FS.open(path, "w"), | |
position = 0, | |
buffer; | |
try { | |
// Wait until consumer has called `next` with a buffer to write | |
while (buffer = await yield null) { | |
let offset = position, | |
position += buffer.length; | |
// Write to file if buffer is not empty | |
if (position > offset) | |
await FS.write(fd, buffer, 0, buffer.length, offset); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
} | |
// Skip past the first iteration in order to prevent data loss | |
var iter = inner(); | |
iter.next(); | |
return iter; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This example uses a decorator function which starts the generator and skips over the first | |
element in the sequence to prevent data loss. | |
*/ | |
import * as FS from "async-fs"; | |
export const readFile = skipFirst(async function*(path) { | |
let fd = await FS.open(path, "r"), | |
position = 0, | |
bytesRead, | |
buffer; | |
try { | |
// Send filled buffer view to consumer and wait until consumer has called | |
// `next` with a buffer to fill. | |
while (buffer = await yield buffer) { | |
// Stop if past EOF | |
if (bytesRead === 0) | |
break; | |
bytesRead = await FS.read(fd, buffer, buffer.length, position); | |
position += bytesRead; | |
buffer = buffer.slice(0, written); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
}); | |
export const writeFile = skipFirst(async function*(path) { | |
let fd = await FS.open(path, "w"), | |
position = 0, | |
buffer; | |
try { | |
// Wait until consumer has called `next` with a buffer to write | |
while (buffer = await yield null) { | |
let offset = position, | |
position += buffer.length; | |
// Write to file if buffer is not empty | |
if (position > offset) | |
await FS.write(fd, buffer, 0, buffer.length, offset); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This example uses a hypothetical keyword `next` to access the argument supplied to the | |
`next` method of the generator object. | |
*/ | |
import * as FS from "async-fs"; | |
export async function* readFile(path) { | |
let fd = await FS.open(path, "r"), | |
position = 0; | |
try { | |
while (true) { | |
// Wait for a buffer from the consumer | |
let buffer = await next; | |
// Read chunk from file into buffer | |
let bytesRead = await FS.read(fd, buffer, buffer.length, position); | |
// Stop if past EOF | |
if (bytesRead === 0) | |
break; | |
position += bytesRead; | |
// Send filled buffer view to consumer | |
yield buffer.slice(0, written); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
} | |
export async function* writeFile(path) { | |
let fd = await FS.open(path, "w"), | |
position = 0; | |
try { | |
while (true) { | |
// Wait for a buffer from the consumer | |
let buffer = await next, | |
offset = position, | |
position += buffer.length; | |
// Write to file if buffer is not empty | |
if (position > offset) | |
await FS.write(fd, buffer, 0, buffer.length, offset); | |
yield null; | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This example overrides the core generator methods and uses a closure variable to | |
provide access to the input argument. | |
*/ | |
import * as FS from "async-fs"; | |
function DataSink(init) { | |
let input = {}, | |
gen = init(input); | |
// Intercept the core generator methods, capturing the input value | |
gen.prototype = new class extends gen.prototype.constructor { | |
next(val) { input.value = val; return super(val); } | |
throw(val) { input.value = val; return super(val); } | |
return(val) { input.value = val; return super(val); } | |
}; | |
return gen; | |
} | |
export const readFile = DataSink(input => async function*(path) { | |
let fd = await FS.open(path, "r"), | |
position = 0; | |
try { | |
while (true) { | |
// Wait for a buffer from the consumer | |
let buffer = await input.value; | |
// Read chunk from file into buffer | |
let bytesRead = await FS.read(fd, buffer, buffer.length, position); | |
// Stop if past EOF | |
if (bytesRead === 0) | |
break; | |
position += bytesRead; | |
// Send filled buffer view to consumer | |
yield buffer.slice(0, written); | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
}); | |
export const writeFile = DataSink(input => async function*(path) { | |
let fd = await FS.open(path, "w"), | |
position = 0; | |
try { | |
while (true) { | |
// Wait for a buffer from the consumer | |
let buffer = await input.value, | |
offset = position, | |
position += buffer.length; | |
// Write to file if buffer is not empty | |
if (position > offset) | |
await FS.write(fd, buffer, 0, buffer.length, offset); | |
yield null; | |
} | |
} finally { | |
await FS.close(fd); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment