Ruby:文件行的长度(以字节为单位)?

我正在编写这个小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时,它都不会被传递,因此这些数字肯定不会匹配。

请参阅相关的镐头部分

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

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

由于缺少方便的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__ == $0 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作为输出,因为后者倾向于提供特定于OS的换行序列。

如果你真的担心多字节字符,可以考虑使用each_byte或unpack(C *)选项和monkey-patching String,如下所示:

 class String def size_in_bytes self.unpack("C*").size end end 

解压缩版本比我机器上的each_byte快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 (根据您之前的post)。 还有EOF文件字符(^ Z)?

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

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

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

还要注意IO#each_line的存在(只是因为你可以扔掉while并且更多一点ruby-idiomatic ;-))。

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

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

顺便说一下,没有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) 

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

  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