Fs.createreadstream
比较佩服nodejs的文档, 真心粗糙啊.
原理
- 首先说fs.createReadStream弄的是一个readable stream
- readable stream 也是一个stream
- stream 就是EventEmitter
- 一切都是文件, 不论键盘, 显示器, 都是文件.
- 一切文件都是流, 实际上都是当做流来处理的. 都是有open, pause, read, close…..等等操作和类似ondata, onend….这样的事件
问题的关键不在原理, 在细节
原型: fs.createReadStream(path[, options])
path, 可以是这三样:
- string
- buffer
- url
options,
- string 特指encode – 参见下面encode的说明
- Object 包含以下8项内容
flags
stringencoding
stringfd
intmode
intautoClose
boolstart
intend
inthighWaterMark
int
就这8项的详解, 好难找啊.
flags
- 这个是读写的模式
- 写入的时候更有用.
- 比如w就是覆盖写
- r+ 就是添加写
fd
- 这个项目会导致忽略很多项目:
- start
- path也会被忽略
- file descriptor
- POSIX 标准规定的
- stdout, stdin and stderr 的编码是0, 1, 2
- 一切都是文件, 就是这个货.
- https://en.wikipedia.org/wiki/File_descriptor
- https://stackoverflow.com/questions/36771266/what-is-the-use-of-fd-file-descriptor-in-node-js/36771339
mode
- 是linux permission
- 只有新建文件的时候有效, 换句话说, 放到这里就和前面的flag一样, 其实一般情况是没用的.
- 那么啥时候有用呢? 我不知道, 有知道的告诉我一声.
autoclose
- 如果他是false, 那么出错和end, 就不会自动关闭流, 他对下面两个事件有影响
- error
- end
- 这是第一个明确有用的内容
encoding
-
buffer可以使用的encoding都是他的取值范围, 以下8种
-
ascii 7bit模式 高位的1个bit会被忽略
-
utf8 1-多byte模式
-
utf16le 2-4byte
-
ucs2 和上面的utf16le是一回事
-
base64 url和filename安全
-
latin1 单byte模式
-
binary 和latin1是一样的
-
hex 两byte模式
-
-
参考:https://nodejs.org/api/buffer.html#buffer_class_method_buffer_from_string_encoding
start end
- 设置读取的文件位置.
- 起止点都包含在读取范围之内.
- 是否可以使用负数?
- 是否可以直接指定读取尾部的128字节?
//例子, 读取一个100字节的文件的最后十个字节
fs.createReadStream('sample.txt', { start: 90, end: 99 });
highwatermark
- 这个项目控制的是chunk的size
- 例如: var rs = fs.createReadStream(‘/foo/bar’, { highWaterMark: 128 * 1024 });
- 参见: https://stackoverflow.com/questions/27641571/changing-readstream-chunksize
官网啥都有, 但是, 结构上很晕.
- https://nodejs.org/api/fs.html
基础内容
- 建议看官网, 这里粗略记录一点, 比如
- 两种模式: 流模式stream和暂停模式pause
- 暂停切换到流模式的三个方法
- data事件处理器
- 显式调用resume
- 调用pipe
- 流切到暂停
- 没有用pipe的情况下, pause即可
- 用了pipe, 那么要做两步
- 溢出data事件的处理器
- 用unpipe断开所有管道
- 各种基础的参数, 函数….
- 异步方法如果要保证顺序, 就要把调用链起来
- csdn这个文章也不错: http://blog.csdn.net/foruok/article/details/49120183
基础函数
- fs.open
- fs.stat
基础数据结构
- buffer
- fs.stats
stats
- 是一个json字符串
- http://nodejs.cn/api/fs.html
fs.stat()
、fs.lstat()
和fs.fstat()
的返回值, 这三个函数只有微妙的不同, node文档并无解释, 解释在linux文档: http://man7.org/linux/man-pages/man2/lstat.2.htmlutil.inspect(stats)
会返回stats的描述字符串. util是node的一个类库: http://nodejs.cn/api/util.html#util_util_inspect_object_options
//util.inspect返回
Stats {
dev: 2114,
ino: 48064969,
mode: 33188,
nlink: 1,
uid: 85,
gid: 100,
rdev: 0,
size: 527,
blksize: 4096,
blocks: 8,
atimeMs: 1318289051000.1,
mtimeMs: 1318289051000.1,
ctimeMs: 1318289051000.1,
birthtimeMs: 1318289051000.1,
atime: Mon, 10 Oct 2011 23:24:11 GMT,
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
//函数
stats.isFile()
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink() (仅对 fs.lstat() 有效)
stats.isFIFO()
stats.isSocket()
- 例如: stats.size就是文件的尺寸(Bytes)
- 或者stats[‘size’]
fs感悟:
- fs就是照搬了linux/unix的文件操作函数.
buffer
- http://nodejs.cn/api/buffer.html
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
- buffer可以认为是typedarray的Uint8Array的一种实现, 对应于c语言的uint8_t
- 不要new, 哈哈, 正合吾意.
- 用这三个函数:
Buffer.from()
、Buffer.alloc()
、和Buffer.allocUnsafe()
c感悟
- js完全可以和c一一对应.
- 之前一个这样的语言是perl, 不小心失败了.
参考
官方文档
- http://wiki.jikexueyuan.com/project/nodejs/file-system.html
- http://nodejs.cn/api/buffer.html
- https://nodejs.org/api/buffer.html
进入html5的领域
- 有一个原生接口叫file: https://developer.mozilla.org/en-US/docs/Web/API/File
https://electronjs.org/docs/api/file-object
拖拽的文件处理
<div id="holder">
Drag your file here
</div>
<script>
document.addEventListener('drop', function (e) {
e.preventDefault();
e.stopPropagation();
for (let f of e.dataTransfer.files) {
console.log('File(s) you dragged here: ', f.path)
}
});
document.addEventListener('dragover', function (e) {
e.preventDefault();
e.stopPropagation();
});
</script>
- 关于file的html5操作, 这个文档讲的很好: https://www.html5rocks.com/en/tutorials/file/dndfiles/
那么目前的问题就是: 如何在electron中操作文件.
- 菜单操作+dialog操作https://stackoverflow.com/questions/38067298/saving-files-locally-with-electron
- 菜单: https://electronjs.org/docs/api/menu
- dialog: https://electronjs.org/docs/api/dialog
- https://electronjs.org/docs/api/dialog#dialogshowsavedialogbrowserwindow-options-callback
- 一个指南: https://ourcodeworld.com/articles/read/106/how-to-choose-read-save-delete-or-create-a-file-with-electron-framework
- electron相关实操参考隔壁的blog
补充一个实例, 如何读取文件尾部的128字节(处理过id3的秒懂)
//文件长度
let filesize
//读取尾部的128字节
fs.stat(sname, initstat)
function initstat(err, data){
filesize= data.size
//读取尾部, 128字节, 由于从0编号, 因此最后一个字节是(长度-1)
const fes=fs.createReadStream(sname, { start: (filesize-128), end: (filesize-1) });
fes.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
tailh.value =chunk
tailb.value =chunk
});
}
总结: 明确的说, 尽量别用read[bytes], 那个并不好, 也是官方不推荐的, 关键就是无法控制是否读好了. 是否能读…
官方推荐的做法还是我上面的做法, 在建立这个流的时候可以设置好位置, 然后, 就用on(‘data’)这样的事件来处理.
参考:
- https://medium.freecodecamp.org/node-js-streams-everything-you-need-to-know-c9141306be93
- https://nodejs.org/api/url.html#url_url_format_url_options
path包很有用啊
- 参考: https://nodejs.org/api/path.html#path_path_join_paths
- 不论是拿目录
- 扩展名
- 文件名
- 都有直接的函数可以用, 相当方便.
- 需要做文件处理的小伙伴建议阅读以下, 就不必自己写正则了.
- 特别要指出的是pathname是path串里去除掉域名的后面的那部分例如:
- url.parse(‘http://stackoverflow.com/questions/17184791’).pathname
- will give: “/questions/17184791”
- 用path, 取文件名.
- https://nodejs.org/api/path.html
- path是需要引入的: const path = require(‘path’);