安全逃离和回读一个文件路径在红宝石
题
我需要保存一些信息有关的一些文件。没什么太花哨所以我想我会去一个简单的一线每项文本的文件。事情是这样的:
# write
io.print "%i %s %s\n" % [File.mtime(fname), fname, Digest::SHA1.file(fname).hexdigest]
# read
io.each do |line|
mtime, name, hash = line.scanf "%i %s %s"
end
当然这不起作用,因为文件的名称可以包含空间(破scanf)和行符(破IO#每个)。
行打破的问题,可以避免的放弃使用的各与会有一堆的获取('')
while not io.eof?
mtime = Time.at(io.gets(" ").to_i)
name = io.gets " "
hash = io.gets "\n"
end
处理空间的名字是另外一个问题。现在,我们需要做一些逃脱。
注:我喜欢空间作为一个记录分隔但我没有问题改变为一个更容易使用。在这种情况下的文件名称虽然是唯一一个可以帮助为ascii nul"\0",而是一nul分隔的文件是不是一个真正的文本的文件了...
我最初有一墙的案文,详细说明的迭代我的奋斗做出正确的逃离职能及其相互但这只是无聊并不是真正有用的。我只是给你的最终结果:
def write_name(io, val)
io << val.gsub(/([\\ ])/, "\\\\\\1") # yes that' 6 backslashes !
end
def read_name(io)
name, continued = "", true
while continued
continued = false
name += io.gets(' ').gsub(/\\(.)/) do |c|
if c=="\\\\"
"\\"
elsif c=="\\ "
continued=true
" "
else
raise "unexpected backslash escape : %p (%s %i)" % [c, io.path, io.pos]
end
end
end
return name.chomp(' ')
end
我不高兴,在所有与read_name.路太长和录音,我觉得这不应该是坚硬的。
同时试图使这项工作中,我试图想出其它的方式:
bittorrent编码/php化的方式:前缀的文件名称与长的名字然后就io.读取(name_len.to_i).它的工作原理,但它是一个真正的皮塔饼编辑的文件。在这一点上,我们一半的二元格式。
串#检查:这一个看起来明确提出为此目的!除了这似乎是唯一的方式获得的价值是通过eval。我不想eval-ing一串我不产生可信的数据。
此。意见?是不是有一些lib它可以做这一切?我失去了一些东西,显而易见?你会怎么做?
解决方案
当你说"节省"你的意思是将信息存储在一个文件?
你可以使用 CSV模块 从红宝石的标准图书馆。这将意味着你的分隔是逗号,而不是空间,但它将处理所有逃逸和unescaping你。
如果一个值包含空间值是封闭在
"quotes"
如果一个值包含报价,然后报价字是逃出为2报价符例如
"hello"
会成为"""hello"""
写的详细信息文件:
require 'csv'
outfile = File.open('csvout', 'wb')
CSV::Writer.generate(outfile) do |csv|
csv << [File.mtime(fname), fname, Digest::SHA1.file(fname).hexdigest]
end
outfile.close
阅读他们的返回:
CSV::Reader.parse(File.open('csvout', 'rb')) do |row|
p row
end
其他提示
CSV,如前所述,是一个好的选择。另一个是其("其不是个标记语言"),这可以处理多个任意数据可以比CSV。这里的一些数据:
require 'pp'
require 'yaml'
h = {
:first_name => 'Fred',
:last_name => 'Flinstone',
:children => ['Bam Bam', 'Pebbles'],
:exclamation => 'Yabba Dabba Doo',
}
让我们编写数据文件在其格式:
File.open('/tmp/foo.yaml', 'w') do |file|
file.write h.to_yaml
end
现在让我们看看有什么其看起来像:
$ cat /tmp/foo.yaml
---
:exclamation: Yabba Dabba Doo
:first_name: Fred
:last_name: Flinstone
:children:
- Bam Bam
- Pebbles
最后,让我们重新建立的数据,从其文件:
pp YAML.load_file('/tmp/foo.yaml')
# => {:exclamation=>"Yabba Dabba Doo",
# => :first_name=>"Fred",
# => :last_name=>"Flinstone",
# => :children=>["Bam Bam", "Pebbles"]}