我正在编写这个小小的HelloWorld,作为这个的后续内容,但这些数字并没有加起来

filename = "testThis.txt"
total_bytes = 0
file = File.new(filename, "r")
file.each do |line|
  total_bytes += line.unpack("U*").length
end
puts "original size #{File.size(filename)}"
puts "Total bytes #{total_bytes}"

结果与文件大小不同。我想我只需要知道我需要插入的 format ...或者我可能完全错过了这一点。 如何逐行测量文件大小?

注意:我在Windows上,文件编码为ANSI。

修改:这会产生相同的结果!

filename = "testThis.txt"
total_bytes = 0
file = File.new(filename, "r")
file.each_byte do |whatever|
  total_bytes += 1
end
puts "Original size #{File.size(filename)}"
puts "Total bytes #{total_bytes}"

所以现在可以提供帮助的人......

有帮助吗?

解决方案

IO#的工作方式与从命令行捕获输入的工作方式相同:“输入”不作为输入的一部分发送;当在文件或IO的其他子类上调用#gets时,它都不会被传递,因此数字肯定不会匹配。

请参阅相关的 Pickaxe部分

我可以问一下为什么你这么关心线长总和到文件大小?你可能正在解决一个比必要更难的问题......

啊哈。我想我现在就明白了。

缺少方便的iPod(或任何其他类型的东西),我不知道你是否想要正好4K块,在这种情况下IO#read(4000)将是你的朋友(4000或4096?)或如果你更乐意分手,在这种情况下,这样的事情应该有效:

class Chunkifier
  def Chunkifier.to_chunks(path)
    chunks, current_chunk_size = [""], 0
    File.readlines(path).each do |line|
      line.chomp! # strips off \n, \r or \r\n depending on OS
      if chunks.last.size + line.size >= 4_000 # 4096?
        chunks.last.chomp! # remove last line terminator
        chunks << ""
      end
      chunks.last << line + "\n" # or whatever terminator you need
    end
    chunks
  end
end

if __FILE__ == 
class String
  def size_in_bytes
    self.unpack("C*").size
  end
end
require 'test/unit' class TestFile < Test::Unit::TestCase def test_chunking chs = Chunkifier.to_chunks(PATH) chs.each do |chunk| assert 4_000 >= chunk.size, "chunk is #{chunk.size} bytes long" end end end end

注意使用IO#readlines来获取所有文本:#each或#each_line也可以。我用String#chomp!为了确保无论操作系统在做什么,都会删除最后的字节,以便\ n或其他任何内容都可以强制输出。

我建议使用File#write而不是#print或#puts作为输出,因为后者倾向于提供特定于操作系统的换行序列。

如果您真的关心多字节字符,请考虑使用each_byte或unpack(C *)选项以及猴子修补字符串,如下所示:

<*>

解压缩版本比我机器上的每个版本快8倍,顺便说一句。

其他提示

您可以尝试IO#each_byte,例如

total_bytes = 0
file_name = "test_this.txt"
File.open(file_name, "r") do |file|
  file.each_byte {|b| total_bytes += 1}
end
puts "Original size #{File.size(file_name)}"
puts "Total bytes #{total_bytes}"

那当然不会一次给你一条线。您最好的选择可能是通过 each_byte 来浏览文件,直到遇到 \ r \ n 。 IO类提供了许多可能有用的低级读取方法。

这里可能有几个重叠的问题:

  1. 换行字符 \ r \ n \ n (根据您之前的帖子)。还有EOF文件字符(^ Z)?

  2. “大小”的定义在您的问题陈述中:您的意思是“多少个字符” (考虑到多字节字符编码)或者你的意思是“多少字节”?

  3. $ KCODE 全局变量的交互(在ruby 1.9中不推荐使用。如果您在1.9下运行,请参阅 String#encoding 和朋友)。例如,您的文件中是否有重音字符?

  4. #unpack 的格式字符串。如果你真的想要计算字节,我想你想要 C *

  5. 还要注意 IO#each_line 的存在(只是这样你就可以丢弃并且更加像一个ruby-idiomatic; - ))。

问题在于,当您在Windows上保存文本文件时,换行符是两个字符(字符13和10),因此2个字节,当您将其保存在linux上时,只有1个(字符10)。但是,ruby将这两个字符报告为单个字符'\ n' - 它表示字符10.更糟糕的是,如果你使用windows文件在linux上,ruby会给你两个字符。

因此,如果您知道您的文件始终来自Windows文本文件并在Windows上执行,那么每次获得换行符时,您都可以为计数添加1。否则它是一些条件和一个小状态机。

BTW没有EOF'字符'。

f = File.new("log.txt")
begin
    while (line = f.readline)
        line.chomp
        puts line.length
    end
rescue EOFError
    f.close
end

这是一个简单的解决方案,假设当前文件指针设置为读取文件中一行的开头:

    last_pos = file.pos
    next_line = file.gets
    current_pos = file.pos
    backup_dist = last_pos - current_pos
    file.seek(backup_dist, IO::SEEK_CUR)

在此示例中“文件”是您正在阅读的文件。要在循环中执行此操作:

    last_pos = file.pos
    begin loop
        next_line = file.gets
        current_pos = file.pos
        backup_dist = last_pos - current_pos
        last_pos = current_pos
        file.seek(backup_dist, IO::SEEK_CUR)
    end loop
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top