windows下《七天学会NodeJS》学习笔记之三--文件操作

小文件拷贝


    var fs = require(‘fs‘);

 

    function copy(src, dst) {//接受源文件地址和目的文件地址

        fs.writeFileSync(dst, fs.readFileSync(src));//从源路径中读取文件内容,然后写入目标路径

    }

 

    function main(argv) {

        copy(argv[0], argv[1]);

    }

 

    main(process.argv.slice(2));//`process`是个全局变量,可通过`process.argv`获得命令行参数。由于`argv[0]`固定等于NodeJS程序文件的绝对路径,`argv[1]`固定等于主模块的绝对路径,因此第一个命令参数从`argv[2]`这个位置开始

大文件拷贝


    var fs = require(‘fs‘);

 

    function copy(src, dst) {

        fs.createReadStream(src).pipe(fs.createWriteStream(dst));//先创建一个源文件的只读数据流,然后创建一个文件的只写数据源,然后用`pipe`方法把两个数据流连接起来,实现边读边写的操作。

    }

 

    function main(argv) {

        copy(argv[0], argv[1]);

    }

 

    main(process.argv.slice(2));

Buffer(数据块)http://nodejs.org/api/buffer.html

  1. JS语言本身只有字符串数据类型,没有二进制数据类型。因此,NodeJS提供了一个与String对等的全局构造函数Buffer来提供对二进制数据的操作。

    典型用法如下:

    
     var bin=new Buffer([0x68,0x65,0x6c,0x6f,0x6f]);//构造一个字符串
    
     console.log(bin.length);    //输出长度
    
     bin[0]; //0x68
    
     var str = bin.toString("UTF-9");//hello,用指定编码将二进制数据转化为字符串;
    
     var bin = new Buffer(‘hello‘, ‘utf-8‘); // => <Buffer 68 65 6c 6c 6f>,将字符串转换为指定编码下的二进制数据
    

    2.Buffer与字符串有一个重要区别。字符串是只读的,并且对字符串的任何修改得到的都是一个新字符串,原字符串保持不变。至于Buffer,更像是可以做指针操作的C语言数组。例如,可以用[index]方式直接修改某个位置的字节。bin[0]
    = 0x48;
    ,而.slice方法也不是返回一个新的Buffer,而更像是返回了指向原Buffer中间的某个位置的指针,因此对.slice方法返回的Buffer的修改会作用于原Buffer

  2. 如果想要拷贝一份Buffer,得首先创建一个新的Buffer,并通过.copy方法把原Buffer中的数据复制过去。这个类似于申请一块新的内存,并把已有内存中的数据复制过去。以下是一个例子。Buffer将JS的数据处理能力从字符串扩展到了任意二进制数据

    
     var bin = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]);
    
     var dup = new Buffer(bin.length);
    
     
    
     bin.copy(dup);
    
     dup[0] = 0x48;
    
     console.log(bin); // => <Buffer 68 65 6c 6c 6f>
    
     console.log(dup); // => <Buffer 48 65 65 6c 6f>
    

Stream(数据流)[http://nodejs.org/api/stream.html)

  1. 当内存中无法一次装下需要处理的数据时或者一边读一边处理文件时,就需要用数据流。NodeJS中通过各种Stream来提供对数据流的操作。Stream基于事件机制工作,所有的Stream的实例都继承于NodeJS提供的EventEmitter
  2. 还是大文件拷贝的例子,创建一个只读数据流
    
     var rs = fs.createReadStream(pathname);          
    
     rs.on(‘data‘, function (chunk) {//`data`事件会被源源不断的触发,不管`doSomething`函数是否处理得过来。
    
         doSomething(chunk);
    
     });
    
     
    
     rs.on(‘end‘, function () {
    
         cleanUp();
    
     });
    

继续改造代码:


     var rs = fs.createReadStream(src);

    rs.on(‘data‘, function (chunk) {//通过回调添加暂停功能,处理完毕后再继续

        rs.pause();

        doSomething(chunk, function () {

            rs.resume();

        });

    });

 

    rs.on(‘end‘, function () {

        cleanUp();

    });

一个读写文件的例子:

var rs = fs.createReadStream(src);

var ws = fs.createWriteStream(dst);


    rs.on(‘data‘, function (chunk) {//如果写的速度太慢,出导致内存溢出

        ws.write(chunk);

    });

 

    rs.on(‘end‘, function () {

        ws.end();

    });

继续改造代码:


    var rs = fs.createReadStream(src);

    var ws = fs.createWriteStream(dst);

 

    rs.on(‘data‘, function (chunk) {

        if (ws.write(chunk) === false) {//.write可以判断是写入目标了还是放了缓存了

            rs.pause();

        }

    });

 

    rs.on(‘end‘, function () {

        ws.end();

    });

 

    ws.on(‘drain‘, function () {//判断是否已经将缓存中的数据写入标目

        rs.resume();

    });

File System(文件系统)[http://nodejs.org/api/fs.html)

  1. NodeJS通过fs内置模块提供对文件的操作。主要有三类:

    • 文件属性读写:fs.stat,fs.chmod,fs.chown
    • 文件内容的读写:fs.readFilefs.readdirfs.writeFilefs.mkdir
    • 底层文件操作:fs.openfs.readfs.writefs.close
  2. fs模块的所有异步API都有对应的同步版本,用于无法使用异步操作时,或者同步操作更方便时的情况。同步API除了方法名的末尾多了Sync外,异常对象与执行结果的传递方式也有相应变化。下面是两个例子:
    
     fs.readFile(pathname, function (err, data) {
    
         if (err) {
    
             // Deal with error.
    
         } else {
    
             // Deal with data.
    
         }
    
     });
    

    对应同步版本:

    
     try {
    
         var data = fs.readFileSync(pathname);
    
         // Deal with data.
    
     } catch (err) {
    
         // Deal with error.
    
     }
    

Path(路径)[http://nodejs.org/api/path.html)

  1. path内置模块用来简化路径相关操作,提高代码可读性。下面是几个常用api。
  2. path.normalize将传入的路径转换为标准路径。它在linux下和windows生成的斜杠不同。
    
       var cache = {};
    
     
    
       function store(key, value) {
    
           cache[path.normalize(key)] = value;
    
       }
    
     
    
       store(‘foo/bar‘, 1);
    
       store(‘foo//baz//../bar‘, 2);
    
       console.log(cache);  // => { "foo/bar": 2 }
    

    2.path.join将路径拼接为标准路径。如path.join(‘fool/‘,‘baz/‘,‘../bar‘);//=>"foo/bar"

  3. path.extname:根据不同的扩展名作不同操作:path.extname(‘foo/bar.js‘);
    // => ".js"

遍历目录

  1. 递归算法:在需要优先考虑性能时,需要把递归算法转换为循环算法,以减少函数调用次数。

    
     function factorial(n) {
    
         if (n === 1) {
    
             return 1;
    
         } else {
    
             return n * factorial(n - 1);
    
         }
    
     }
    
  2. 遍历算法:目录是一个树状结构,在遍历时一般使用深度优先+先序遍历算法。深度优先,意味着到达一个节点后,首先接着遍历子节点而不是邻居节点。先序遍历,意味着首次到达了某节点就算遍历完成,而不是最后一次返回某节点才算数。因此使用这种遍历方式时,下边这棵树的遍历顺序是A > B > D > E > C > F。
    
               A
    
              / \
    
             B   C
    
            / \   \
    
           D   E   F
    
    • 同步遍历

      function travel(dir, callback) {

      
        fs.readdirSync(dir).forEach(function (file) {
      
            var pathname = path.join(dir, file);
      
       
      
            if (fs.statSync(pathname).isDirectory()) {
      
                travel(pathname, callback);
      
            } else {
      
                callback(pathname);
      
            }
      
        });
      

      }

    • 异步遍历

      function travel(dir, callback, finish) {

      
        fs.readdir(dir, function (err, files) {
      
            (function next(i) {
      
                if (i < files.length) {
      
                    var pathname = path.join(dir, files[i]);
      
       
      
                    fs.stat(pathname, function (err, stats) {
      
                        if (stats.isDirectory()) {
      
                            travel(pathname, callback, function () {
      
                                next(i + 1);
      
                            });
      
                        } else {
      
                            callback(pathname, function () {
      
                                next(i + 1);
      
                            });
      
                        }
      
                    });
      
                } else {
      
                    finish && finish();
      
                }
      
            }(0));
      
        });
      

      }

文本编码

  1. 常用文本编码有UTF8GBK两种,并且:UTF8可能还带有BOM。在读取不同编码的文本文件时,需要将文件内容转换为JS使用的UTF8编码字符串后才能正常处理。
  2. 移除BOM:BOM用于标记一个文本文件使用Unicode编码,其本身是一个Unicode字符("\uFEFF"),位于文本文件头部。在不同的Unicode编码下,BOM字符对应的二进制字节如下:
    
         Bytes      Encoding
    
     ----------------------------
    
         FE FF       UTF16BE
    
         FF FE       UTF16LE
    
         EF BB BF    UTF8
    

    以下代码实现了识别和去除UTF8 BOM的功能。

    
     function readText(pathname) {
    
         var bin = fs.readFileSync(pathname);
    
     
    
         if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) {
    
             bin = bin.slice(3);
    
         }
    
     
    
         return bin.toString(‘utf-8‘);
    
     }
    
  3. GBK编码不在NodeJS自身支持范围内,因此,我们一般借助iconv-lite第三方包来转换编码。下载该NPM后,可下边方式编写一个读取GBK文本文件的函数。
    
     var iconv = require(‘iconv-lite‘);
    
     
    
     function readGBKText(pathname) {
    
         var bin = fs.readFileSync(pathname);
    
     
    
         return iconv.decode(bin, ‘gbk‘);
    
     }
    
  4. 单字节编码,如果无法预知文件编码,可以使用单字节编码来读取文件,不用关心文件是GBK还是UTF8编码。
    
     1. GBK编码源文件内容:
    
         var foo = ‘中文‘;
    
     2. 对应字节:
    
         76 61 72 20 66 6F 6F 20 3D 20 27 D6 D0 CE C4 27 3B
    
     3. 使用单字节编码读取后得到的内容:
    
         var foo = ‘{乱码}{乱码}{乱码}{乱码}‘;
    
     4. 替换内容:
    
         var bar = ‘{乱码}{乱码}{乱码}{乱码}‘;
    
     5. 使用单字节编码保存后对应字节:
    
         76 61 72 20 62 61 72 20 3D 20 27 D6 D0 CE C4 27 3B
    
     6. 使用GBK编码读取后得到内容:
    
         var bar = ‘中文‘;
    

    上述例子说明直接操作单字节乱码字符时,背后对应的字节保持不变。

    NodeJS自带了一种binary编码可以用来实现这个方法,如下:

    
     function replace(pathname) {
    
         var str = fs.readFileSync(pathname, ‘binary‘);
    
         str = str.replace(‘foo‘, ‘bar‘);
    
         fs.writeFileSync(pathname, str, ‘binary‘);
    
     }
    
时间: 2024-12-21 18:40:01

windows下《七天学会NodeJS》学习笔记之三--文件操作的相关文章

python学习笔记(三):文件操作和集合

这篇博客来说一下python对文件的操作. 对文件的操作分三步: 1.打开文件获取文件的句柄,句柄就理解为这个文件 2.通过文件句柄操作文件 3.关闭文件. 现有以下文件file.txt: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 寂寞当然有一点 你不在我身边 总是特别想念你的脸 距离是一份考卷 测量

黑马程序员--Java基础学习笔记【文件操作、递归】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 文件操作 文件和目录路径名的抽象表示形式. 成员变量 StringpathSeparator= File.pathSeparator; // 路径分隔符 System.out.println(pathSeparator); // ; Stringseparator= File.separator;// 默认名称分隔符 System.out.println(separator); // \ 构造

【nodejs学习】1.文件操作

1.小文件拷贝,使用nodejs内置模块 var fs = require('fs'); function copy(src, dst){ fs.writeFileSync(dst, fs.readFileSync(src)); } function main(argv){ copy(argv[0], argv[1]); } main(process.argv.slice(2)); 解释:process是一个全局变量,可通过procress.argv获得命令行参数,argv[0]固定等于node

黑马程序员——JAVA学习笔记十一(文件操作File)

为了很方便的代表文件的概念,以及存储一些对于文件的基本操作,在java.io包中设计了一个专门的类——File类. 在File类中包含了大部分和文件操作的功能方法,该类的对象可以代表一个具体的文件或文件夹,所以以前曾有人建议将该类的类名修改成FilePath,因为该类也可以代表一个文件夹,更准确的说是可以代表一个文件路径. 1.创建文件 1)boolean java.io.File.createNewFile() throws IOException用来创建文件,如果文件存在,创建失败,返回fa

PKU C++程序设计实习 学习笔记4 文件操作和模板

第七章 文件操作和模板 7.1 文件操作 7.2 函数模板 泛型程序设计(Generic Programming) 算法实现时不指定具体要操作的数据的类型 泛型--算法实现一遍,适用于多种数据结构 优势: 减少重复代码的编写 两种类型 函数模板 类模板 与"抽象.封装.继承.多态"并列 函数模板 template<class 类型参数1, class 类型参数2, - > 返回值类型 模板名 (形参表) { 函数体 } 例子,交换两个变量值的函数模板 template &l

python学习笔记4-python文件操作

python文件操作 open r:以读方式打开 w:以写方式打开 a:以追加模式 r+:读写模式 w+:读写模式(参见w) a+:读写模式(参见a) rb:以二进制读模式打开 wb:以二进制写模式打开(参见w) ab:以二进制追加模式打开(参见a) rb+:以二进制读写模式打开(参见r+) wb+:以二进制读写模式打开(参见w+) ab+:以二进制读写模式打开(参见a+) with open 使用for循环遍历文件 打开文件 [[email protected] ~]# vim forread

windows下《七天学会NodeJS》学习笔记之二--代码的组织和部署

本系列第一篇:<windows下<七天学会NodeJS>学习笔记之一--NodeJS基础>,请参见这儿:http://blog.csdn.net/fm2005/article/details/41348813 模块路径解析规则:nodejs支持三种解析方式:/或C:开头的绝对路径:./开头的绝对路径:按照一定规则解析路径,直到找到模块位置. 内置模块:如果传递给require的是NodeJS内置模块名称,则不解析,直接返回内部模块导出对象. node_modules目录:node_

nodejs学习笔记之安装、入门

由于项目需要,最近开始学习nodejs.在学习过程中,记录一些必要的操作和应该注意的点. 首先是如何安装nodejs环境?(我用的是windows 7环境,所以主要是windows 7的例子.如果想看linux下的安装可以参考http://www.cnblogs.com/meteoric_cry/archive/2013/01/04/2844481.html) 1. nodejs提供了一些安装程序,可以去官网(http://nodejs.org/download/)按照自己的机器进行下载,下载完

Nodejs学习笔记(三)——一张图看懂Nodejs建站

前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广. 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇<Nodejs学习笔记(二)——Eclipse中运行调试Nodejs>之后,代码编写环境就从Sublime转战到Eclipse下,感觉顺手多了.于是就跟着Scott老师学起了Nodejs建站的课程(推荐大家点进去看看),踏上了未爬先走的路子. 作为一个白里透白的小白来说,今天主要记录下如何用Nodejs搭建一个小小的网站,以及自己对于这种Nodejs建站的运