Ruby处理YAML和json的方法,用什么方法处理更精准
ruby处理yaml
ruby的标准库yaml基于psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/psych.html
require 'yaml'
之后,为大多数的基本数据类型都提供了 to_ yaml()
方法,用于将各数据类型的对象转换为yaml格式。
例如:
require 'yaml' require 'set' p "hello world".to_yaml p 123.to_yaml p %w(perl shell php).to_yaml p ({ one: 1, two: 2} ).to_yaml p set.new([1,2,3]).to_yaml
得到:
"--- hello world\n" "--- 123\n" "---\n- perl\n- shell\n- php\n" "---\n:one: 1\n:two: 2\n" "--- !ruby/object:set\nhash:\n 1: true\n 2: true\n 3: true\n"
也可以使用yaml.dump()
方法实现和to_yaml相同的功能,它还可以写入文件。
users = [{ name: 'bob', permissions: ['read']} , { name: 'alice', permissions:['read', 'write']} ] file.open("/tmp/a.yml","w") { |f| yaml.dump(users, f) }
查看文件:
--- - :name: bob #=> 注意,保留了hash源数据中的符号 :permissions: - read - :name: alice :permissions: - read - write
用yaml.load()从yaml中读取数据:
require 'yaml' pp yaml.load(data) __end__ mysql: passwd: p@ssword1! user: root port: 3306 other1: nil other2: false other3: "" hosts: - ip: 10.10.1.1 hostname: node1 - ip: 10.10.1.2 hostname: node2
得到:
{ "mysql"=> { "passwd"=> "p@ssword1!", #=> 注意,key是string而非symbol "user"=> "root", "port"=> 3306, "other1"=> "nil", "other2"=> false, "other3"=> "", "hosts"=> [{ "ip"=> "10.10.1.1", "hostname"=> "node1"} , { "ip"=> "10.10.1.2", "hostname"=> "node2"} ]} }
如果想让hash的key是符号而非字符串,可以设置选项symbolize_names: true
:
pp yaml.load(data, symbolize_names: true)
需要注意,yaml可以将对象进行序列化,所以有几方面注意事项:
- 在反序列化的时候需要也require涉及到的文件,例如对set类型序列化后,在反序列化时如不
require 'set'
则无法还原对象 - 有些底层对象不能序列化,包括io流、ruby代码对象proc、binding等
- 不要反序列化不被信任的数据对象(比如用户输入的数据),此时可使用safe_load(),它默认只允许加载以下几种类型的数据:
- trueclass
- falseclass
- nilclass
- numeric
- string
- array
- hash
- 如果确实想要加载额外的数据类型,可以在safe_load()中指定参数permitted_classes: []或permitted_symbols: []
ruby处理json数据
转为json格式字符串
使用json.generate()可以将对象或数组转换为json格式的数据:
require 'json' p json.generate "abc" p json.generate 123 p json.generate true p json.generate nil p json.generate [2,3,4] p json.generate({ name: "junmajinlong", age: 23} ) require 'set' p json.generate(set.new([1,23,44]))
得到:
"\"abc\"" "123" "true" "null" "[2,3,4]" "{ \"name\":\"junmajinlong\",\"age\":23} " "\"#set: { 1, 23, 44} > \""
当require 'json'
后,很多ruby类型都具备了一个to_json的方法,可以直接将该类型的数据转换为json数据:
p ({ name: "junmajinlong", age: 23} ).to_json p (set.new([1,23,44])).to_json
得到:
"{ \"name\":\"junmajinlong\",\"age\":23} " "\"#set: { 1, 23, 44} > \""
此外,json.dump()也可以将对象转换为json格式的字符串,而且它还支持写入文件:
hsh = { name: "junmajinlong", age: 23} file.open("/tmp/a.json", "w") { |f| json.dump(hsh, f)}
json格式字符串转为ruby对象
要从json格式字符串转为ruby对象,有一些选项可设置,参考https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/json.html#method-i-parse,比如*symbolize_names*
选项表示是否将jsonobject中的key解析为符号类型的key,如果设置为false,则解析为字符串的key。
要将json格式的字符串解析为ruby数据类型(hash),使用json.parse()
,
require 'json' hsh = '{ "name": "junmajinlong", "age": 23} ' p json.parse(hsh) p json.parse(hsh, symbolize_names: true)
注意,上面的json字符串必须是合理的json数据,比如key必须使用双引号包围而不能使用单引号,字符串必须使用双引号包围,等等。比如"{
'name': 'junmajinlong', 'age': 23}
"
就不是合理的json字符串。
要从json文件中读取json数据并转换为ruby数据,使用load():
data = file.open("/tmp/a.json") do |f| json.load(f) end pp data #=> { "name"=> "junmajinlong", "age"=> 23}
自定义对象的转换方式
json支持的数据类型有:
- 字符串
- 数值
- 对象
- 数组
- 布尔
- null
从一种语言的数据转换为json数据时,如果数据类型也是json所支持的,可直接转换,但如果包含了json不支持的类型,则可能报错,也可能以一种对象字符串的方式保存,这取决于对应的实现。
可以在对象中定义as_json
实例方法来决定对象如何转换为json字符串,再定义类方法from_json()
来决定如何从json字符串中恢复为一个对象。
例如,
require 'json' require 'date' class person attr_accessor :name, :birthday def initialize name, birthday @name = name @birthday = datetime.parse(birthday) end end file.open("/tmp/p.json", "w") do |f| json.dump(person.new("junmajinlong", "1999-10-11"), f) end
查看保存的json数据:
$ cat /tmp/p.json "#person:0x00007fffc7e575d0> "
定义as_json
和frmo_json
:
require 'json' require 'date' class person attr_accessor :name, :birthday def initialize name, birthday @name = name @birthday = datetime.parse(birthday) end def as_json { name: @name, birthday: @birthday.strftime("%f") } end def self.from_json json data = json.parse(json) new(data["name"], data["birthday"]) end end
之后要序列化、反序列化该对象,可:
data = person.new("junmajinlong", "1999-10-11").as_json p data p1=person.from_json(json.dump data) p p1.birthday
如果是读写json文件,可:
person1 = person.new("junmajinlong", "1999-10-11") file.open("/tmp/p.json", "w") do |f| json.dump(person1.as_json, f) end p1 = file.open("/tmp/p.json") do |f| person.from_json(f.read) # person.from_json(json.load(f).to_json) end p p1
几种json解析工具的性能测试
测试了json标准库、oj和fast_josnparser解析json的性能,测试项包括:
- 从文件中加载并解析json字符串为ruby对象
- 从内存json字符串中解析json字符串为ruby对象
- 带有symbolize_keys/symbolize_names转换时的解析
- json标准库和oj将ruby对象dump为json字符串
- json标准库和oj将ruby对象dump为json字符串保存到文件
注:
- fast_jsonparser没有dump功能,只有解析json字符串功能
- oj在将对象转换为json字符串时,可能会丢失数据的精度,比如浮点数的精度
测试的json字符串数量大约50m。
测试了ruby 2.7.1和ruby 3.0.1两个版本,gem包的版本信息如下:
fast_jsonparser (0.5.0) json (default: 2.5.1) oj (3.11.7)
测试代码:
require 'benchmark' require 'json' require 'oj' require 'fast_jsonparser' # warm json_file='test' # 文件大小大约50m str = file.read(json_file) ######## json puts " load file ".center(80, '-') benchmark.bm(30) do |x| x.report("json.load:") { file.open(json_file){ |f| json.load(f) } } x.report("oj.load_file:") { oj.load_file(json_file) } x.report("fastjsonparser.load:") { fastjsonparser.load(json_file) } end puts puts " load file with symbolize_keys ".center(80, '-') benchmark.bm(30) do |x| x.report("json.load:") { file.open(json_file){ |f| json.load(f, nil, symbolize_names: true, create_additions: false) } } x.report("oj.load_file:") { oj.load_file(json_file, symbol_keys: true) } x.report("fastjsonparser.load:") { fastjsonparser.load(json_file, symbolize_keys: true) } end puts puts " parse str ".center(80, '-') benchmark.bm(30) do |x| x.report("json.parse:") { json.parse(str) } x.report("oj.load:") { oj.load(str) } x.report("fastjsonparser.parse:") { fastjsonparser.parse(str) } end puts puts " parse str with symbolize_keys ".center(80, '-') benchmark.bm(30) do |x| x.report("json.parse:") { json.parse(str, symbolize_names: true) } x.report("oj.load:") { oj.load(str, symbol_keys: true) } x.report("fastjsonparser.parse:") { fastjsonparser.parse(str, symbolize_keys: true) } end obj = json.parse(str, symbolize_names: true) puts puts " dump json to str ".center(80, '-') benchmark.bm(30) do |x| x.report("json.dump:") { json.dump(obj) } x.report("oj.dump:") { oj.dump(obj) } end puts puts " dump json to file ".center(80, '-') benchmark.bm(30) do |x| x.report("json.dump:") { file.open('0_json_dump', 'w') { |f| json.dump(obj, f) } } x.report("oj.to_file:") { oj.to_file('0_oj_dump', obj) } end
测试结果:
ruby 2.7.1中:
---------------------------------- load file ----------------------------------- user system total real json.load: 1.591831 0.058021 1.649852 ( 1.738119) oj.load_file: 1.350385 0.057684 1.408069 ( 2.434268) -慢 fastjsonparser.load: 0.653968 0.103258 0.757226 ( 0.848913) -快 ------------------------ load file with symbolize_keys ------------------------- user system total real json.load: 1.212617 0.039052 1.251669 ( 1.349545) oj.load_file: 1.432059 0.098950 1.531009 ( 2.679610) -慢 fastjsonparser.load: 0.695538 0.008384 0.703922 ( 0.797081) -快 ---------------------------------- parse str ----------------------------------- user system total real json.parse: 1.343596 0.000000 1.343596 ( 1.350368) oj.load: 1.133612 0.000000 1.133612 ( 1.140939) fastjsonparser.parse: 0.701701 0.012340 0.714041 ( 0.720296) -快 ------------------------ parse str with symbolize_keys ------------------------- user system total real json.parse: 1.250775 0.000000 1.250775 ( 1.258796) oj.load: 1.131296 0.000000 1.131296 ( 1.138020) fastjsonparser.parse: 0.697433 0.015962 0.713395 ( 0.719439) -快 ------------------------------- dump json to str ------------------------------- user system total real json.dump: 1.374611 0.028454 1.403065 ( 1.403081) oj.dump: 1.025049 0.040184 1.065233 ( 1.065246) -快 ------------------------------ dump json to file ------------------------------- user system total real json.dump: 1.234362 0.040246 1.274608 ( 1.369214) oj.to_file: 1.168707 0.000000 1.168707 ( 1.270957)
ruby 3.0.1中:
---------------------------------- load file ----------------------------------- user system total real json.load: 1.362151 0.083610 1.445761 ( 1.569754) oj.load_file: 1.343601 0.182046 1.525647 ( 2.684472) -慢 fastjsonparser.load: 2.634435 0.052734 2.687169 ( 2.776105) -慢 ------------------------ load file with symbolize_keys ------------------------- user system total real json.load: 1.287954 0.018572 1.306526 ( 1.409770) oj.load_file: 1.478750 0.043847 1.522597 ( 2.668882) -慢 fastjsonparser.load: 2.717857 0.006164 2.724021 ( 2.822728) -慢 ---------------------------------- parse str ----------------------------------- user system total real json.parse: 1.242225 0.008661 1.250886 ( 1.304554) oj.load: 1.097922 0.000000 1.097922 ( 1.110031) fastjsonparser.parse: 2.602679 0.017232 2.619911 ( 2.634604) -慢 ------------------------ parse str with symbolize_keys ------------------------- user system total real json.parse: 1.368262 0.000000 1.368262 ( 1.380730) oj.load: 1.332349 0.000000 1.332349 ( 1.346331) fastjsonparser.parse: 2.706804 0.007238 2.714042 ( 2.726935) -慢 ------------------------------- dump json to str ------------------------------- user system total real json.dump: 1.724653 0.009250 1.733903 ( 1.733912) oj.dump: 1.298235 0.030041 1.328276 ( 1.328279) -快 ------------------------------ dump json to file ------------------------------- user system total real json.dump: 1.765664 0.040595 1.806259 ( 1.905785) oj.to_file: 1.228744 0.020309 1.249053 ( 1.349684) -快 =end
性能测试结论:
- (1).ruby 3之前,fast_jsonparser非常快,但是ruby 3中的fast_jsonparser很慢
- (2).oj解析本地json字符串的性能比标准库json性能稍好,但oj从文件中加载并解析json的速度很慢
- (3).oj将ruby对象解析为json字符串的效率比json标准库性能好
即:
dump: oj.dump > json.dump ruby3 之前: fastjsonparser.load > json.load > oj.load_file fastjsonparser.parse > oj.load > json.parse ruby3 之后: json.load > oj.load_file > fastjsonparser.load oj.load > json.parse > fastjsonparser.parse
multi_json
有一个名为multi_json的gem包,它提供多种json包的功能,默认采用oj作为json的适配引擎。它支持下面几种json适配器:
- ojoptimized json by peter ohler
- yajlyet another json library by brian lopez
- jsonthe default json gem with c-extensions (ships with ruby 1.9+)
- json purea ruby variant of the json gem
- nsjsonserializationwrapper for apple’s nsjsonserialization in the cocoa framework (macruby only)
- gson.rba ruby wrapper for google-gson library (jruby only)
- jrjacksonjruby wrapper for jackson (jruby only)
- okjsona simple, vendorable json parser
如果oj已被require,则默认采用oj处理json,如果oj没有被require,而是require了yajl,则采用yajl处理json,依次类推。
它提供了load()和dump()方法:
load(json_str, options = { } ) options: symbolize_keys: true, false adapter: oj, json_gem, yajl, json_pure, ok_json dump(object, options = { } )
感谢各位的阅读,以上就是“Ruby处理YAML和json的方法,用什么方法处理更精准”的内容了,通过以上内容的阐述,相信大家对Ruby处理YAML和json的方法,用什么方法处理更精准已经有了进一步的了解,如果想要了解更多相关的内容,欢迎关注网络,网络将为大家推送更多相关知识点的文章。
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: Ruby处理YAML和json的方法,用什么方法处理更精准
本文地址: https://pptw.com/jishu/654316.html