资讯专栏INFORMATION COLUMN

快速去除UTF-8 BOM

zhangke3016 / 2774人阅读

摘要:后文所用的测试文件是一个阿里云导出的文件,,测试时文件已缓存显示的接近用去用看一下方法耗时较大,因为会对每一行都进行处理,但是实际上只有第一行有,所以浪费了。

工作中多多少少都会遇到UTF-8 BOM(后面直接叫BOM),有时第三方工具不支持就要自己去掉BOM,例如阿里云导出的SQL文件是有BOM的,但是Navicat不支持,这就要去掉BOM了。

后文所用的测试文件是一个阿里云导出的SQL文件,265M,测试时文件已缓存(time显示的 File system inputs接近0)

用sed去BOM
sed -e "1s/^xefxbbxbf//" file

用time看一下sed方法耗时:

$ /usr/bin/time -v sed -e "1s/^xefxbbxbf//" sqlResult_1601835.sql > /dev/null
        ...
        User time (seconds): 0.33
        System time (seconds): 0.11
        Percent of CPU this job got: 98%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.46
        ...

User time较大,因为sed会对每一行都进行处理,但是实际上只有第一行有BOM,所以浪费了CPU。

sed还支持原地更新(-i):

$ /usr/bin/time -v sed -e "1s/^xefxbbxbf//" sqlResult_1601835.sql -i
        ...
        User time (seconds): 1.31
        System time (seconds): 3.89
        Percent of CPU this job got: 71%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:07.32
        ...

因为会写入文件,所以会更慢,用strace可以发现,sed是通过输出到临时文件然后覆盖原文件实现更新的

open("sqlResult_1601835.sql", O_RDONLY) = 3
open("./sedGlXm60", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
...
rename("./sedGlXm60", "sqlResult_1601835.sql")
用tail去BOM
tail --bytes=+4 file

用tail可以直接跳过BOM,然后直接复制文件内容,减少了不必要的CPU处理:

$ /usr/bin/time -v tail --bytes=+4 sqlResult_1601835.sql > /dev/null
        ...
        User time (seconds): 0.01
        System time (seconds): 0.12
        Percent of CPU this job got: 96%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.14
        ...

但是tail必须自己重定向到新文件再覆盖旧文件。

strip-bom

为了结合sed和tail的优点,我写了一个strip-bom,支持原地更新文件。

先测试一下重定向:

$ /usr/bin/time -v php strip-bom.phar sqlResult_1601835.sql > /dev/null
        ...
        User time (seconds): 0.11
        System time (seconds): 0.22
        Percent of CPU this job got: 98%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.35
        ...

只比sed快了20%,User time少了但System time增加了。因为是个循环读写的过程,每次循环就是一次read和write调用,所以我增加了一个参数来调节每次读的块大小,可以减少循环次数和系统调用,可以比sed快60%:

$ /usr/bin/time -v php strip-bom.phar -b 16384 sqlResult_1601835.sql > /dev/null
        ...
        User time (seconds): 0.06
        System time (seconds): 0.12
        Percent of CPU this job got: 96%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.19

测试原地更新,比sed快30%:

$ /usr/bin/time -v php strip-bom.phar -i -b 16384 sqlResult_1601835.sql
        User time (seconds): 0.23
        System time (seconds): 0.67
        Percent of CPU this job got: 17%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:05.11
copy_file_range

Linux 4.5增加了一个系统调用:

ssize_t copy_file_range(int fd_in, loff_t *off_in,
                               int fd_out, loff_t *off_out,
                               size_t len, unsigned int flags);

可以直接在两个文件描述符间复制内容,而且通常只要一个系统调用,所以可以参考sed复制到临时文件,然后覆盖旧文件,实现代码在:Gist

测试:

$ /usr/bin/time -v ./copy_file_range sqlResult_1601835.sql
        ...
        User time (seconds): 0.00
        System time (seconds): 2.47
        Percent of CPU this job got: 37%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:06.52

减少了系统调用也只比sed快一点,复制到临时文件还是比strip-bom原地更新慢。

dos2unix去BOM

一直以为dos2unix就是转CRLF的,看Feng_Yu评论之后看了man page,原来dos2unix功能很多,其中有去BOM的选项(-r):

$ /usr/bin/time -v dos2unix -r sqlResult_1601835.sql
dos2unix: 正在转换文件 sqlResult_1601835.sql 为Unix格式...
        Command being timed: "dos2unix -r sqlResult_1601835.sql"
        User time (seconds): 10.01
        System time (seconds): 0.90
        Percent of CPU this job got: 60%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:18.20

dos2unix实现类似sed,也是写到临时文件再覆盖,也和sed一样,会处理每一行,所以性能并不好。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26272.html

相关文章

  • 代码组织和部署 文件操作 node.js

    代码组织和部署 模块的路径解析规则 require支持/或者盘符的绝对路径,也支持./开头的相对地址同时require也支持第三种写法 内置模块 如果传递给require的函数是node.js的内置模块,将会不做路径解析,直接返回内部exports模块要导出的对象 node_modules目录 node.js定义一个node_modules存放模块,每次使用foo/bar的方式的时候,会先寻找该目...

    Cc_2011 评论0 收藏0
  • 记一次由BOM引起的bug

    摘要:今天团队小伙伴给了我一个配置文件,可以用如下替代毕竟内容不是重点考虑到这个并不需要常驻,就没有用来引用,因为模块的缓存机制,势必会导致内存泄漏问题的发生,就采取了以下方式但是诡异的事情发生了,竟然报错了此时一脸懵逼,就用了的方式试了一下发现 bug 今天团队小伙伴给了我一个json配置文件,可以用如下替代(毕竟内容不是重点): { text: this is a example...

    cc17 评论0 收藏0
  • Java 跨域 Json字符转类对象

    摘要:前言对于从其他服务器的获得数据,我们一般都为数据传输,比如服务器要从服务器的获得分页信息,得到字符后如果可以方便快捷操作要转为自己的对象。第二种是的,这种就是无报错,但是对象的值一直为空。把值传进去去除报头测试结果是成给对象赋值了 前言 对于从其他服务器的url获得数据,我们一般都为json数据传输,比如服务器B要从服务器A的url获得分页信息,得到json字符后如果可以方便快捷操作要...

    blastz 评论0 收藏0
  • 网站常见安全问题记录(持续更新)

    摘要:由此造成即使页面的或者设置为,也无法让整个网页紧贴浏览器顶部,因为在一开头有这个隐藏字符解决办法保存文件为建议不要用记事本打开开发文件 说明 初衷: 本文档用于记录所遇到的网站安全问题,并分类汇总,方便后期遇到类似问题,能够快速找到解决方案,提高效率,让程序员有更多的时间去把妹,LOL... 记录规范: 标题必须清晰明了,方便用户快速查找,拒绝标题党; 问题放到正确的分类中; 记录问...

    Jason_Geng 评论0 收藏0

发表评论

0条评论

zhangke3016

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<