1

一部のファイルに関するいくつかの情報を保存する必要があります。あまり凝ったものではないので、1 項目につき 1 行のシンプルなテキスト ファイルを使用することにしました。このようなもの :

# 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#each の改行) を含めることができるからです。

改行の問題は、each の使用をやめて、一連の get(' ') を使用することで回避できます。

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.read(name_len.to_i) だけを付けます。動作しますが、ファイルを手動で編集するのは本当にピタです。この時点で、バイナリ形式への途中段階です。

  • String#inspect : これは、その目的のために明示的に作成されたように見えます! ただし、値を戻す唯一の方法は eval を使用することです。信頼できるデータから生成したのではない文字列を評価するという考えは嫌いです。

そう。意見 ? これをすべて実行できるライブラリはありませんか?明らかな何かが欠けていますか?どうやってそれをしますか?

4

2 に答える 2

1

「保存」とは、情報をファイルに保存するという意味ですか?

Ruby 標準ライブラリのCSV モジュールを使用できます。これは、区切り文字がスペースではなくコンマであることを意味しますが、すべてのエスケープとエスケープ解除を処理します。

  • 値にスペースが含まれている場合、その値を囲む"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
于 2010-05-13T20:52:16.680 に答える
1

前述のように、CSV は適切な選択です。もう 1 つは YAML (「Yaml はマークアップ言語ではない」) で、CSV よりも任意のデータを処理できます。ここにいくつかのデータがあります:

require 'pp'
require 'yaml'

h = {
  :first_name => 'Fred',
  :last_name => 'Flinstone',
  :children => ['Bam Bam', 'Pebbles'],
  :exclamation => 'Yabba Dabba Doo',
}

データを YAML 形式でファイルに書き込みましょう。

File.open('/tmp/foo.yaml', 'w') do |file|
  file.write h.to_yaml
end

YAML がどのように見えるか見てみましょう。

$ cat /tmp/foo.yaml
---
:exclamation: Yabba Dabba Doo
:first_name: Fred
:last_name: Flinstone
:children:
- Bam Bam
- Pebbles

最後に、YAML ファイルからデータを再構成しましょう。

pp YAML.load_file('/tmp/foo.yaml')
# => {:exclamation=>"Yabba Dabba Doo",
# =>  :first_name=>"Fred",
# =>  :last_name=>"Flinstone",
# =>  :children=>["Bam Bam", "Pebbles"]}
于 2010-05-13T22:01:01.983 に答える