如何从一个大文件中分离小文件

如何从一个大文件中分离小文件

月光魔力鸭

2018-09-12 10:24 阅读 138 喜欢 0 nodejs 文件切割

背景

互联网应用经常需要存储用户上传的图片,比如facebook相册。

facebook目前存储了2600亿张照片,总大小为20PB,每张照片约为80KB。用户每周新增照片数量为10亿。(总大小60TB),平均每秒新增3500张照片(3500次写请求),读操作峰值可以达到每秒百万次。

考虑到一台标配的服务器的硬盘是10TB,理论上可以存 10TB/80KB=1.3亿张左右的照片。

然而linux服务器的文件索引的设计最多只支持500w左右的文件数,如果超过500w,性能会大幅下降。

在普通的linux文件系统中,读取一个文件包括三次磁盘io:首先读取目录元数据到内存,其次把文件中的inode节点装载到内存,最后读取实际的文件内容。由于小文件个数太多,无法将所有的目录以及文件的inode信息缓存到内存,因此磁盘IO次数很难达到每个图片读取只需要一次磁盘IO的理想状态。

因此,facebook的图片存储系统haystack设计采用的思路是: 多个逻辑图片文件共享一个物理文件。

1个物理文件的大小=32MB。因此linux服务器中的文件个数在 10TB/32MB=1024*1024/32=327680..远远小于linux服务器的文件索引的阈值。

照片文件在物理文件中的存放为依次的顺序存放。每个照片文件的存放规格如下:

- 1字节的标记位。0代表接下来的照片仍然可用,1代表接下来的照片已经被删除,2代表该物理文件接下来已经没有图片了。

- 4字节的size。标记照片的大小x。

- x字节,照片文件本身。
实现

首先,文件已经到手,现在的目标是,根据规则,将文件的所有图片解出。

思路:...没有思路 读取,然后循环,然后写入即可。

代码:

var fs = require('fs');

var d = fs.readFileSync('rf.data');
var b = new Buffer(d);
var c = 0;
for(var i=0;i<b.length;){
    var start = i;
    var flag = b.slice(start,start+1);//获得标志位
    flag = getR(flag);
    if(flag == 0){
        var size = getR(b.slice(start+1,start+5));
        //将图片输出
        fs.writeFile(c+'.jpg',b.slice(start+5,start+6+size),function(){
            console.log('图片写入完成')
        });
        i = i + 1 + 4 + size;
        c++;
    }else if(flag == 1){
        var size =getR( b.slice(start+1,start+5));
        i = i + 1 + 4 + size;
    }else if(flag == 2){
        i = b.length;
    }
}

function getR ( buf ){
    return parseInt(buf.toString('hex'),16);
}

额,对于我个人的难点在于 16进制转 10进制..

  1. 首先将BUFFER 转成字符串,buffer内为16进制的,转成string ,则调用Buffer.toString('hex');
    //其中buffer的 toString 还支持以下几个类型encode
    utf8
    hex
    ascii
    binary
    base64
    utf-16le
  2. 然后获得16进制的字符串,然后见字符串转化为10进制的数字
    var str = 'ff';
    parseInt(str,16);
    //以下转化
    var a = 'ff';//字符串
    parseInt(a,16);//255
    var a = 0xff;
    a.toString(10);//"255"
    //如果想把16进制转化为10进制
    var a = 0xff;
    parseInt(a)
    parseInt(a.toString(16))

转载请注明出处: https://chrunlee.cn/article/bigfile-split-picture.html


感谢支持!

赞赏支持
提交评论
评论信息(请文明评论)
暂无评论,快来快来写想法...
推荐
关于js的编译和压缩,之前做过一个小工具了,主要就是自己项目成员大都没有这部分的技能,导致发布的时候总需要去编译压缩下.. 最终做了个命令行小工具.. 问题不在这里,前一阵子做压缩的时候发现压缩后竟然是undefined.最终才发现是es6的语法问题。
想做微信/支付宝支付很久了..奈何需要的资质太多,只能慢慢申请,等待,审核..终于下来了。
从豆瓣转到网易云后,发现了不少好听的歌曲,然鹅..当我想把这些歌拿下来扔车上听的时候发现竟然不允许下载..能听不能下?这不科学,作为一名程序猿,必然要迎难而上啊.
通过pm2来实现nodejs应用的集群,不过我之前没做session共享,导致.. 登录不上啊 啊啊啊,无奈,又重新对redis进行了集成。
前几天给朋友帮忙,想要一个一模一样的网站...自告奋勇去帮忙.. 结果发现之前一直没处理过类似的情况,虽然也写过爬虫,不过看了下网站,也不算麻烦。于是简单实现了这个自动抓站的功能,最终整理成为一个自动抓站的工具,能省很多的事情。
介绍几个日常开发中常用的几个小工具: anywhere / anywhere-auth / watchlessc / changeext
经常会遇到需要系统重启后自动执行的一些任务,在windows 上可以将对应的程序打包成service 然后自启动即可
最近在折腾的时候又想写less了,但是换框架了,成了thinkjs,考虑到开发阶段一直编译编译less的情况..最终根据middleware的特点实现了一个超级简单的less中间件。