1. ruby读取二进制文件
用字符串存放 自定义位数的二进制数 便可。 例如: #include<stdio.h> #include <stdlib.h> main(){ char s[33]="01110111"
; // 二进制数 int x; x = strtol(s,NULL,2)
; // 把2进制数 转换为 int 型 printf("%#x %d\n",x,x)
; // 输出它的 16进制数值 和 10进制 数值。 return 0; } 另外有个函数 itoa() 可以把int 型 数值 转换为 (二进,十进,十六进制书写的) 字符串。
2. ruby 写文件
ERB文件是ERB语言编写的源代码文件,ERB语言本质上是Ruby模板语言。ERB文件可以包含ERB源代码的任何类型的文本,其他编程语言的代码也可以保存在ERB文件中。
即使ERB文件可以包含许多不同类型的文本和源代码,但保存在文件中的ERB代码还是有区别的。当与ERB模板引擎一起运行时,该代码会在结果文件中生成其他文本。
由于Ruby ERB更像是一种模板语言,因此ERB文件也用作创建其他文件的模板,主要是网页文件,例如.RB,.RHTML,.HTML和.JS文件。
3. ruby读取文件内容
可以离线使用。
Apifox功能
接口设计:Apifox 接口文档遵循 OpenApi 3.0 (原 Swagger)、JSON Schema 规范的同时,提供了非常好用的可视化文档管理功能,零学习成本,非常高效。并且支持在线分享接口文档。
接口调试:Postman 有的功能,比如环境变量、前置/后置脚本、Cookie/Session 全局共享 等功能,Apifox 都有,并且比 Postman 更高效好用。接口运行完之后点击保存为用例按钮,即可生成接口用例,后续可直接运行接口用例,无需再输入参数,非常方便。自定义脚本 100% 兼容 Postman 语法,并且支持运行javascript、java、python、php、js、BeanShell、go、shell、ruby、lua等各种语言代码。
接口用例:通常一个接口会有多种情况用例,比如参数正确用例、参数错误用例、数据为空用例、不同数据状态用例等等。运行接口用例时会自动校验数据正确性,用接口用例来调试接口非常高效。
接口数据 Mock:内置 Mock.js 规则引擎,非常方便 mock 出各种数据,并且可以在定义数据结构的同时写好 mock 规则。支持添加“期望”,根据请求参数返回不同 mock 数据。最重要的是 Apifox 零配置 即可 Mock 出非常人性化的数据,具体在本文后面介绍。
数据库操作:支持读取数据库数据,作为接口请求参数使用。支持读取数据库数据,用来校验(断言)接口请求是否成功。
接口自动化测试:提供接口集合测试,可以通过选择接口(或接口用例)快速创建测试集。目前接口自动化测试更多功能还在开发中,敬请期待!目标是:JMeter 有的功能基本都会有,并且要更好用。
快捷调试:类似 Postman 的接口调试方式,主要用途为临时调试一些无需文档化的接口,无需提前定义接口即可快速调试。
代码生成:根据接口及数据数据模型定义,系统自动生成接口请求代码、前端业务代码及后端业务代码。
团队协作:Apifox 天生就是为团队协作而生的,接口云端实时同步更新,成熟的团队/项目/成员权限管理,满足各类企业的需求。
4. ruby命令
1、App Store
2、Homebrew
3、各类官方网站(非官方的不建议)
1和3都非常简单,下载就行
重点介绍下2
Homebrew
Homebrew,是一款Mac OS平台下的软件包管理工具,对于macos平台的软件安装非常有用,效率高,而且避开了App Store(我其实很讨厌App Store,但对于专业软件而言很多时候又很难绕开)
好长时间没用过这个玩意了,今天突然用到,给大家提一提,如果买了mac还没用起来的,12分推荐安装。
Homebrew这个工具支持安装、卸载、更新、查看、搜索等很多实用的功能。通过命令行直接进行软件包的安装,可以无需关注诸多依赖问题(我在ubuntu/centos/suselinux..上经常会遇到直接安装rpm包的场景,依赖问题通常让人吐血又没有太好的解决办法)
如果还是不知道这个是什么呢,我们可以把它类比成:apt-get、yum、zypper、npm、pip,我能想到的差不多就这么多了,再不知道,你只能先用用看了。
官方对于这个管理工具的定位是:Homebrew installs the stuff you need that Apple (or your Linux system) didn’t.
什么意思呢?简单就是苹果装不了的东西,我来装!硬核!
软件安装通过以下命令来完成安装:
brew install xx
安装后可以通过如下命令来进行一些查看和学习,当然也可以通过官方的指导书来学习,奉上链接:https://docs.brew.sh
安装非常简单,这里提一下
首先是一些基本要求需要满足:(官方有四条,删除了两条屁话)
macOS High Sierra (10.13) (or higher) 2
Command Line Tools (CLT) for Xcode: xcode-select --install,developer.apple.com/downloads or Xcode 3
安装命令如下(以前貌似还有个ruby命令安装的):
mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
安装完成后有个源要注意下,这个是国外软件,通常这类包管理软件的源都是默认只想国外的网站的,那么使用的时候,下载速度会特别慢(装个依赖多、包又大的软件,能等到你蛋碎)
以下参考的清华大学的mirror,我平常用的还算比较多(另外比较多的是163和淘宝两个源,都很不错)
git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git
git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git
brew update
如果需要还原(我估计没人需要。。。。)
git -C "$(brew --repo)" remote set-url origin https://github.com/Homebrew/brew.git
git -C "$(brew --repo homebrew/core)" remote set-url origin https://github.com/Homebrew/homebrew-core.git
git -C "$(brew --repo homebrew/cask)" remote set-url origin https://github.com/Homebrew/homebrew-cask.git
brew update
5. ruby读写文件
1、Apache Flume
官网:https://flume.apache.org/
Flume 是Apache旗下的一款开源、高可靠、高扩展、容易管理、支持客户扩展的数据采集系统。 Flume使用JRuby来构建,所以依赖Java运行环境。
Flume最初是由Cloudera的工程师设计用于合并日志数据的系统,后来逐渐发展用于处理流数据事件。
Flume设计成一个分布式的管道架构,可以看作在数据源和目的地之间有一个Agent的网络,支持数据路由。
每一个agent都由Source,Channel和Sink组成。
Source
Source负责接收输入数据,并将数据写入管道。Flume的Source支持HTTP,JMS,RPC,NetCat,Exec,Spooling Directory。其中Spooling支持监视一个目录或者文件,解析其中新生成的事件。
Channel
Channel 存储,缓存从source到Sink的中间数据。可使用不同的配置来做Channel,例如内存,文件,JDBC等。使用内存性能高但不持久,有可能丢数据。使用文件更可靠,但性能不如内存。
Sink
Sink负责从管道中读出数据并发给下一个Agent或者最终的目的地。Sink支持的不同目的地种类包括:HDFS,HBASE,Solr,ElasticSearch,File,Logger或者其它的Flume Agent。
Flume在source和sink端都使用了transaction机制保证在数据传输中没有数据丢失。
Source上的数据可以复制到不同的通道上。每一个Channel也可以连接不同数量的Sink。这样连接不同配置的Agent就可以组成一个复杂的数据收集网络。通过对agent的配置,可以组成一个路由复杂的数据传输网络。
配置如上图所示的agent结构,Flume支持设置sink的Failover和Load Balance,这样就可以保证即使有一个agent失效的情况下,整个系统仍能正常收集数据。
Flume中传输的内容定义为事件(Event),事件由Headers(包含元数据,Meta Data)和Payload组成。
Flume提供SDK,可以支持用户定制开发:
Flume客户端负责在事件产生的源头把事件发送给Flume的Agent。客户端通常和产生数据源的应用在同一个进程空间。常见的Flume客户端有Avro,log4J,syslog和HTTP Post。另外ExecSource支持指定一个本地进程的输出作为Flume的输入。当然很有可能,以上的这些客户端都不能满足需求,用户可以定制的客户端,和已有的FLume的Source进行通信,或者定制实现一种新的Source类型。
同时,用户可以使用Flume的SDK定制Source和Sink。似乎不支持定制的Channel。
2、Fluentd
官网:http://docs.fluentd.org/articles/quickstart
Fluentd是另一个开源的数据收集框架。Fluentd使用C/Ruby开发,使用JSON文件来统一日志数据。它的可插拔架构,支持各种不同种类和格式的数据源和数据输出。最后它也同时提供了高可靠和很好的扩展性。Treasure Data, Inc 对该产品提供支持和维护。
Fluentd的部署和Flume非常相似:
Fluentd的架构设计和Flume如出一辙:
Fluentd的Input/Buffer/Output非常类似于Flume的Source/Channel/Sink。
Input
Input负责接收数据或者主动抓取数据。支持syslog,http,file tail等。
Buffer
Buffer负责数据获取的性能和可靠性,也有文件或内存等不同类型的Buffer可以配置。
Output
Output负责输出数据到目的地例如文件,AWS S3或者其它的Fluentd。
Fluentd的配置非常方便,如下图:
Fluentd的技术栈如下图:
FLuentd和其插件都是由Ruby开发,MessgaePack提供了JSON的序列化和异步的并行通信RPC机制。
Cool.io是基于libev的事件驱动框架。
FLuentd的扩展性非常好,客户可以自己定制(Ruby)Input/Buffer/Output。
Fluentd从各方面看都很像Flume,区别是使用Ruby开发,Footprint会小一些,但是也带来了跨平台的问题,并不能支持Windows平台。另外采用JSON统一数据/日志格式是它的另一个特点。相对去Flumed,配置也相对简单一些。
3、Logstash
https://github.com/elastic/logstash
Logstash是著名的开源数据栈ELK (ElasticSearch, Logstash, Kibana)中的那个L。
Logstash用JRuby开发,所有运行时依赖JVM。
Logstash的部署架构如下图,当然这只是一种部署的选项。
一个典型的Logstash的配置如下,包括了Input,filter的Output的设置。
几乎在大部分的情况下ELK作为一个栈是被同时使用的。所有当你的数据系统使用ElasticSearch的情况下,logstash是首选。
4、Chukwa
官网:https://chukwa.apache.org/
Apache Chukwa是apache旗下另一个开源的数据收集平台,它远没有其他几个有名。Chukwa基于Hadoop的HDFS和Map Reduce来构建(显而易见,它用Java来实现),提供扩展性和可靠性。Chukwa同时提供对数据的展示,分析和监视。很奇怪的是它的上一次github的更新事7年前。可见该项目应该已经不活跃了。
Chukwa的部署架构如下:
Chukwa的主要单元有:Agent,Collector,DataSink,ArchiveBuilder,Demux等等,看上去相当复杂。由于该项目已经不活跃,我们就不细看了。
5、Scribe
代码托管:https://github.com/facebookarchive/scribe
Scribe是Facebook开发的数据(日志)收集系统。已经多年不维护,同样的,就不多说了。
6、Splunk Forwarder
官网:http://www.splunk.com/
以上的所有系统都是开源的。在商业化的大数据平台产品中,Splunk提供完整的数据采金,数据存储,数据分析和处理,以及数据展现的能力。
Splunk是一个分布式的机器数据平台,主要有三个角色:
Search Head负责数据的搜索和处理,提供搜索时的信息抽取。
Indexer负责数据的存储和索引
Forwarder,负责数据的收集,清洗,变形,并发送给Indexer
Splunk内置了对Syslog,TCP/UDP,Spooling的支持,同时,用户可以通过开发Script Input和Modular Input的方式来获取特定的数据。在Splunk提供的软件仓库里有很多成熟的数据采集应用,例如AWS,数据库(DBConnect)等等,可以方便的从云或者是数据库中获取数据进入Splunk的数据平台做分析。
这里要注意的是,Search Head和Indexer都支持Cluster的配置,也就是高可用,高扩展的,但是Splunk现在还没有针对Farwarder的Cluster的功能。也就是说如果有一台Farwarder的机器出了故障,数据收集也会随之中断,并不能把正在运行的数据采集任务Failover到其它的Farwarder上。
总结
我们简单讨论了几种流行的数据收集平台,它们大都提供高可靠和高扩展的数据收集。大多平台都抽象出了输入,输出和中间的缓冲的架构。利用分布式的网络连接,大多数平台都能实现一定程度的扩展性和高可靠性。
其中Flume,Fluentd是两个被使用较多的产品。如果你用ElasticSearch,Logstash也许是首选,因为ELK栈提供了很好的集成。Chukwa和Scribe由于项目的不活跃,不推荐使用。
Splunk作为一个优秀的商业产品,它的数据采集还存在一定的限制,相信Splunk很快会开发出更好的数据收集的解决方案。
End.
6. java读取解析二进制文件
我们知道在计算机内存中,存储的是二进制数据,在网络传输中,也是二进制数据,但最终呈现给用户的是字符串,二进制与字符串的转化就需要编码、解码的参与,如果世界上只有一种字符编码方式,就不会有乱码这一说了,但事实是,编码的方式太多了,utf-8、utf-32、utf-16、gbk、gb2312、iso-8859-1、big5、unicode等等。由于每个编码的规则不一样,一般都不能用一种进行编码,用另一种进行解码。如utf-8中,一个字母用一个字节表示,一个汉字用三个字节表示,特殊的汉字用四个字节表示,而gbk中,一个字母用一个字节表示,一个汉字用两个字节表示。
有一个说法,内存中存储的二进制是unicode码,如果内存中的数据需要存储或传输时,才会进行一次转化,将unicode码转化成其它的编码二进制(有待考证)。个人觉得这种方式很合理,毕竟unicode码中每个字符都有独一无二的二进制与之对应。
排查乱码问题,难度在于是在哪个环节出了问题,但乱码的本质都是一样的,读取二进制的编码和最初将字符串转化成二进制的编码方式不一致。
此处说明一个概念,编码指将字符串转化成二进制,解码指将二进制转化成字符串。
UTF-8编码,GBK解码
在这我们讨论一下,gbk和utf-8互转的乱码问题,直接上代码。
package com.anjz.test;
import java.io.UnsupportedEncodingException;
public class CodingTest {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "你好,世界";
System.out.println("字符串长度:"+str.length());
byte[] utfBytes = str.getBytes("utf-8");
System.out.println("utf-8需要"+utfBytes.length+"字节存储");
byte[] gbkBytes = str.getBytes("gbk");
System.out.println("gbk需要"+gbkBytes.length+"字节存储");
}
}
以上代码运行打印出一下内容:
字符串长度:5
utf-8需要15字节存储
gbk需要10字节存储
可以看出,utf-8存储一个汉字,需要3个字节,gbk存储一个汉字,需要2个字节。
现用单个字符测试。
package com.anjz.test;
import java.io.UnsupportedEncodingException;
public class CodingTest {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "你";
byte[] utfBytes = str.getBytes("utf-8");
for(byte utfByte:utfBytes){
//字节对应的十进制是负数,因java中的二进制使用补码表示的,此处使用0xff 还原成int表示的数据,再转化成16进制
System.out.print(Integer.toHexString((utfByte & 0xFF)) +",");
}
System.out.println();
String utf2gbkStr = new String(str.getBytes("utf-8"),"gbk");
System.out.println("utf-8转化成gbk:"+utf2gbkStr);
byte[] gbkBytes = utf2gbkStr.getBytes("gbk");
for(byte gbkByte:gbkBytes){
System.out.print(Integer.toHexString((gbkByte & 0xFF))+",");
}
System.out.println();
String gbk2utfStr = new String(utf2gbkStr.getBytes("gbk"),"utf-8");
System.out.println("gbk转化成utf-8:"+gbk2utfStr);
}
}
运行上面代码,得出的结果:
e4,bd,a0,
utf-8转化成gbk:浣�
e4,bd,3f,
gbk转化成utf-8:�?
用两个字符测试,将上述代码String str = “你”改成String str = “你好”。运行代码,得出的结果:
e4,bd,a0,e5,a5,bd,
utf-8转化成gbk:浣犲ソ
e4,bd,a0,e5,a5,bd,
gbk转化成utf-8:你好
上述实验中,utf-8转化成gbk出现乱码,这个很好理解,但是再还原回去,gbk转化成utf-8,单个中文字符依然是乱码,两个字符却能正常显示,这个到底是怎么回事呢?
经过一番研究,想把这个事说明白,还需要从它们的编码规则着手。
ISO-8859-1
单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
GBK
采用单双字节变长编码,英文使用单字节编码,完全兼容ASCII字符编码,中文部分采用双字节编码。双字节其编码范围从8140至FEFE(剔除xx7F)。
单字节:00000000 - 01111111
双字节:10000001 01000000 - 11111110 11111110 (剔除******** 01111111)
单字节、双字节的区分通过高字节高位区分,单字节高位为0,双字节的高字节高位为1。
UTF-8
可变长字符编码,是unicode码的具体实现,UTF-8用1到6个字节编码Unicode字符。
UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
明白上述GBK和UTF-8的编码规则,我们再分析一下,单个中文字符是乱码,两个字符却能正常显示的问题。
“你”
UTF-8编码对应的二进制:11100100 10111101 10100000
将上述二进制通过GBK进行解码,根据GBK规则,第一个字节高位为1,使用双字节编码,
“11100100 10111101”解码成“浣”,“10100000”对于GBK来说是非法的,就解码成了一种特殊字符“�”。
看看能不能将“浣�”还原回“你”呢?
GBK编码对应的二进制:11100100 10111101 00111111
看到上述的二进制,根本不符合UTF-8编码规则,故用UTF-8进行解码,是解码成了一些特殊字符“�?”。
对于上述情况可以看出,一个二进制,如果不符合当前的编码规则,会被解码成特殊字符,但此特殊字符再进行编码,是回不到最初的二进制的。
用同样的方式,分析“你好”为什么最终可以正常显示。
UTF-8编码对应的二进制:11100100 10111101 10100000 11100101 10100101 10111101
将上述二进制通过GBK进行编码,根据GBK规则,使用双字节编码,“1100100 10111101”解码成“浣”,“10100000 11100101”解码成“犲”,“10100101 10111101”解码成“ソ”。
看看能不能将“浣犲ソ”还原成“你好”呢?
GBK 编码对应的二进制:11100100 10111101 10100000 11100101 10100101 10111101
可以看出二进制是可以被还原的,将此二进制通过UTF-8解码,肯定能变成“你好”。
可以看出,一个字符串,通过UTF-8进行编码,再通过GBK进行解码,再将得到的字符串进行GBK编码,最后将得到的二进制通过UTF-8解码,能否还原到最初的字符串,在于UTF-8编码后得到的二进制,是否符合GBK的编码规则,如果符合,最终就可以还原,如果不符合,就不可还原。
GBK编码,UTF-8解码
package com.anjz.test;
import java.io.UnsupportedEncodingException;
public class CodingTest {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "你好";
byte[] gbkBytes = str.getBytes("gbk");
for(byte gbkByte:gbkBytes){
//字节对应的十进制是负数,因java中的二进制使用补码表示的,此处使用0xff 还原成int表示的数据,再转化成16进制
System.out.print(Integer.toHexString((gbkByte & 0xFF)) +",");
}
System.out.println();
String gbk2utfStr = new String(str.getBytes("gbk"),"utf-8");
System.out.println("gbk转化成utf-8:"+gbk2utfStr);
byte[] utfBytes = gbk2utfStr.getBytes("utf-8");
for(byte utfByte:utfBytes){
System.out.print(Integer.toHexString((utfByte & 0xFF))+",");
}
System.out.println();
String utf2gbkStr = new String(gbk2utfStr.getBytes("utf-8"),"gbk");
System.out.println("utf-8转化成gbk:"+utf2gbkStr);
}
}
运行上述代码,结果为:
c4,e3,ba,c3,
gbk转化成utf-8:���
ef,bf,bd,ef,bf,bd,ef,bf,bd,
utf-8转化成gbk:锟斤拷锟�
上述结果应该都在意料之中,我们通过上述的方法分析一下。
“你好”GBK编码的二进制:11000100 11100011 10111010 11000011
GBK编码的二进制数据,完全匹配不了UTF-8的编码规则,最终UTF-8只能按如下方式匹配,查看第一个字节,开头“110”,理论上匹配两个字节,但看下一个字节,开头却不是“10”,最终“11000100”解码成“�”,看第二个字节开头是“1110”,理论匹配三个字节,看下个字节符合,以“10”开头,但下下个字节开头是“110”,不符合匹配,最终“11100011 10111010”解码成“�”,同理“11000011”也解码成“�”,这个符号都是为找不到对应规则随意匹配的一个特殊字符。
“���”UTF-8编码的二进制为:11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101
这个二进制和原先的二进制不相同,根本转化不到最初的字符串,按照GBK的编码规则,“11101111 10111111”编码成“锟”,“10111101 11101111” 编码成“斤”,“10111111 10111101”编码成“拷”,“11101111 10111111”编码成“锟”,“10111101”不符合GBK规则,编码成特殊字符“�”。
理论上说,用GBK编码,UTF-8解码的字符串是不能还原到最初的字符串的,因UTF-8编码规则的特殊性,GBK编出的二进制,是很难匹配上的。
总结
理论上说,系统出现乱码,将乱码还原到最初的样子,上述UTF-8编码,GBK解码,这个有时是可以还原的,有时是还原不了的,要看UTF-8编码的二进制是否都能符合GBK的编码规则,但GBK编码,UTF-8解码,这个基本是条不归路。
但实际中,有一种情况,是100%可以将乱码还原成最初的字符串。就是任意编码格式编码,ISO-8859-1解码,这个主要因为ISO-8859-1是单字节编码,而且匹配所有单字节情况,乱码字符串总是可以还原到最初的二
- 相关评论
- 我要评论
-