Pregunta

Estoy escribiendo este pequeño HelloWorld como seguimiento de this y los números no cuadran

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}"

El resultado no es el mismo que el tamaño del archivo. Creo que solo necesito saber qué formato necesito conectar ... o tal vez me haya perdido el punto por completo. ¿Cómo puedo medir el tamaño del archivo línea por línea?

Nota: Estoy en Windows, y el archivo está codificado como tipo ANSI.

Editar: ¡Esto produce los mismos resultados!

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}"

así que cualquiera que pueda ayudar ahora ...

¿Fue útil?

Solución

IO # gets funciona igual que si estuviera capturando datos desde la línea de comando: el " Enter " no se envía como parte de la entrada; tampoco se pasa cuando se invoca #gets en un archivo u otra subclase de IO, por lo que los números definitivamente no coincidirán.

Consulte la sección Pickaxe

relevante

¿Puedo preguntar por qué está tan preocupado por las longitudes de línea que suman el tamaño del archivo? Es posible que esté resolviendo un problema más difícil de lo necesario ...

Ajá. Creo que lo entiendo ahora.

Al carecer de un iPod práctico (o de cualquier otro tipo, para el caso), no sé si quieres exactamente trozos 4K, en cuyo caso IO # read (4000) sería tu amigo (4000 o 4096?) o si está más contento de romper por línea, en cuyo caso algo como esto debería funcionar:

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

Tenga en cuenta el uso de IO # readlines para obtener todo el texto de una sola vez: #each o #each_line también funcionarían. ¡Utilicé String # chomp! para garantizar que, independientemente de lo que esté haciendo el sistema operativo, se eliminen los bytes al final, de modo que \ n o lo que sea se pueda forzar a la salida.

Sugeriría usar File # write, en lugar de #print o #puts para la salida, ya que estos últimos tienden a entregar secuencias de nueva línea específicas del sistema operativo.

Si realmente le preocupan los caracteres de varios bytes, considere tomar las opciones each_byte o unpack (C *) y la cadena de parches de mono, algo como esto:

<*>

La versión descomprimida es aproximadamente 8 veces más rápida que la de cada byte en mi máquina, por cierto.

Otros consejos

Puede probar IO # each_byte, por ejemplo

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}"

Eso, por supuesto, no te da una línea a la vez. Su mejor opción para eso es probablemente revisar el archivo a través de each_byte hasta que encuentre \ r \ n . La clase IO proporciona un montón de métodos de lectura de nivel bastante bajo que podrían ser útiles.

Posiblemente tenga varios problemas superpuestos aquí:

  1. Caracteres de salto de línea \ r \ n vs. \ n (según su publicación anterior). ¿También el carácter de archivo EOF (^ Z)?

  2. Definición de " tamaño " en su enunciado del problema: ¿quiere decir "cuántos caracteres"? (teniendo en cuenta las codificaciones de caracteres de varios bytes) o quieres decir "cuántos bytes"?

  3. Interacción de la variable global $ KCODE (en desuso en ruby ??1.9. Vea String # encoding y amigos si está ejecutando bajo 1.9). ¿Hay, por ejemplo, caracteres acentuados en su archivo?

  4. Su cadena de formato para #unpack . Creo que quieres C * aquí si realmente quieres contar bytes.

Tenga en cuenta también la existencia de IO # each_line (solo para que pueda tirar el while y ser un poco más rubí idiomático; -)).

El problema es que cuando guarda un archivo de texto en Windows, los saltos de línea son dos caracteres (caracteres 13 y 10) y, por lo tanto, 2 bytes, cuando lo guarda en Linux solo hay 1 (carácter 10). Sin embargo, ruby ??informa que ambos son un solo carácter '\ n': dice el carácter 10. Lo que es peor, es que si estás en Linux con un archivo de Windows, ruby ??te dará ambos caracteres.

Entonces, si sabe que sus archivos siempre provienen de archivos de texto de Windows y se ejecutan en Windows, cada vez que obtiene un carácter de nueva línea puede agregar 1 a su conteo. De lo contrario, son un par de condicionales y una pequeña máquina de estados.

Por cierto no hay EOF 'personaje'.

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

Aquí hay una solución simple, suponiendo que el puntero del archivo actual esté configurado al comienzo de una línea en el archivo leído:

    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)

en este ejemplo " archivo " es el archivo del que estás leyendo. Para hacer esto en un bucle:

    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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top