Node.Js与Java的IO流,及底层会发生的故事。

首先,我们来看Node.Js读取文件的操作

var http = require('http');
var fs = require('fs');
var path = require('path');
//文件读取
var server = http.createServer(function (req, res) {
    var fileName = path.resolve(__dirname, 'input.txt');
    fs.readFile(fileName, function (err, data) {
        res.end(data);
    });
});
server.listen(8888); 

这样就可以读取到同级目录下的input.txt文件了,仔细看代码,也没问题,可是当遇到文件比较大,有一个G,两个G呢?代码就不能这样写了,这个时候,就应该用stream流了:

var http = require('http');
var fs = require('fs');
var path = require('path');
//以流的方式文件读取。

var http = require('http');
var fs = require('fs');
var path = require('path');

var server = http.createServer(function (req, res) {
    var fileName = path.resolve(__dirname, 'data.txt');
    var stream = fs.createReadStream(fileName);  //创建一个读的流
    stream.pipe(res); // 将 res 作为 stream 的 接受者
});
server.listen(8888); 

input.txt照样可以输出到网页。于是,我们现在详细讲一下这个流:

图片摘自菜鸟教程

为什么要用流呢?我们把要输入的文件,比作一个水桶,我们要抱起他,要用很大力气,这里的力气指的是
计算机硬件的性能, CPU 的运算,内存的存储,硬盘和网络的读写速度。但是我们没必要抱起它,弄一个水管就好了,这就是stream的作用,同理,我们看视频,也是同一个道理,不可能全部加载完再让你看。

知道了流的原理,那我们写一个文件拷贝吧:

Node版本

let fileName1 = path.resolve(__dirname,'input.txt');
let fileName2 = path.resolve(__dirname,'input1.txt');
let readStream = fs.createReadStream(fileName1);
let writeStream = fs.createWriteStream(fileName2);
readStream.pipe(writeStream);
readStream.on("end",function(){
    console.log("拷贝完成");
})

Java版本,字节流(适合二进制文件,图片,视频,音频 ):

public static void demo() throws IOException {
    //1.获取目标路径
    //第一种方法:通过字符串
    //String srcPath = "图片路径";
    //String destPath = "图片路径";
    //第二种方法:通过文件类
    File srcPath = new File("图片路径");
    File destPath = new File("图片路径");
    //2.创建通道,依次 打开输入流,输出流
    FileInputStream fis = new FileInputStream(srcPath);
    FileOutputStream fos = new FileOutputStream(destPath);
    byte[] bt = new byte[1024];
    //3.读取和写入信息(边读取边写入)
    while (fis.read(bt) != -1) { //读取
        fos.write(bt); //写入
    }
    //4.依次 关闭流(先开后关,后开先关)
    fos.close();//先关输出流
    fis.close();//后关输入流
}

Java版本,字符流:(只能读文本之类的文件,但字符流提供缓冲(Buffer)功能可以提高读取效率。)

public static void demo() throws IOException {
    //获取目标路径
    File srcPath = new File("图片路径");
    File destPath = new File("图片路径");
    //创建通道,依次 打开输入流,输出流
    FileReader fis = new FileReader(srcPath);
    FileWriter fos = new FileWriter(destPath);
    char[] ch = new char[1024];
    int length = 0;
    // 读取和写入信息(边读取边写入)
    while ((length = fis.read(ch)) != -1) { //读取
        fos.write(ch, 0, length); //写入
        fos.flush();
    }
    // 依次 关闭流(先开后关,后开先关)
    fos.close();//先关输出流
    fis.close();//后关输入流
}
菜鸟教程IO示意图

IO流就讲这么多了,其实就是数据不停地搬入搬出缓冲区Buffer而已,上面提到了Buffer缓冲区,以及读取二进制文件,拷贝功能,这就不得不扯到一个底层的东西,那就是操作系统。上面的代码,Java工资5k可以写出来,工资5w,也可以写出来,还有可能写的一样,但是Java5k的人,只会写出这段代码,而5w的人,不仅可以写出这段代码,还理解操作系统的底层原理,还可以自己用底层,自己实现一个IO类,这就是区别。下面就是操作系统的讲解啦,如果想要工资1W+,这东西是必须知道的!

操作系统

关于操作系统,最近在准备软件设计师的考试,以及考研,也会考到操作系统的知识,下面有些理论是抄自书上的。

五大IO模型

IO是什么?,I就是从硬盘到内存,O就是从内存到硬盘。关于五大IO模型,我用白话文讲述下,因为官方文档,挺绕的。
(1)阻塞:
我从硬盘读取数据,然后程序一直等,数据读完后,继续操作。这种方式是最简单的,程序多了,自然就不行了。
(2)非阻塞
我从硬盘读取数据,然后程序跑,我去做其他事,等跑完了,再叫我做事。
(3)IO多路复用
多路复用在网络中,也经常用到,比如HTTP2,多路就是一个线程有多个IO,如果还被阻塞,有一个,或多个成功了,就返回调用。需要线程遍历全部IO,判断是哪个IO有数据。例如Java网络里的socket 的 select() 函数,线程调用 select() 进入阻塞态,任何一个IO有数据了,线程就退出阻塞态,获得机会继续执行。
(4)信号驱动IO
给一个IO注册一个信号和信号触发的回调函数,一旦信号被触发,回调函数里读取数据。
例如给 socket 注册一个“可读”的信号,当数据来了,可读的时候,信号被触发,执行回调函数从内核cache复制数据到用户空间。
(5)异步IO
异步IO中,操作系统完成了数据从内核到用户空间的拷贝后,以信号的方式通知用户线程可以下一步操作。省去了用户线程阻塞下来拷贝数据的过程。

用户空间和内核空间:

内核空间:Java的IO操作都是由操作系统来执行的,比如磁盘到内存,内存到磁盘,都是发生在内核空间的。
用户空间:JVM的堆(进程的内存空间)在这里的程序和指令是访问IO是--被限制的,只能通过内核去访问硬件,不能JVM直接访问IO,因为安全性问题。
Linux就是这样子的,关于这个,体系比较庞大,都可以取一个专题了。

原理

(1)用户程序发起读操作,导致“ syscall read ”系统调用,操作系统接收到调用后,会创建一个缓冲区Buffer,用来存放需要读取的数据。
(2)创建后,同时向IO设备(设备控制器)发送读取指令(包括读哪些内容),IO硬件接收到指令后,进行读取,并把数据通过DMA(直接存取器)放入内核空间的缓冲区中(Buffer)。
(3)操作系统将内核缓冲区中的数据拷贝到用户空间的缓存中,用户发起写操作,导致 “syscall write ”系统调用,将会把一个 buffer 中的数据搬出去,写到磁盘文件,小文件为普通IO,大文件为zerocopy技术。(4)Buffer其实可以理解成一个中转站,在java,php,node中都会用到,比如页面静态化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容