Domanda

Sto scrivendo questo piccolo HelloWorld come seguito di questo e i numeri non si sommano

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

Il risultato non è uguale alla dimensione del file. Penso di aver solo bisogno di sapere quale formato devo collegare ... o forse ho perso del tutto il punto. Come posso misurare le dimensioni del file riga per riga?

Nota: sono su Windows e il file è codificato come tipo ANSI.

Modifica: questo produce gli stessi risultati!

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

quindi chiunque possa aiutare adesso ...

È stato utile?

Soluzione

IO # funziona allo stesso modo di quando stavi acquisendo input dalla riga di comando: il " Enter " non viene inviato come parte dell'input; né viene passato quando #gets viene chiamato su un File o su un'altra sottoclasse di IO, quindi i numeri sicuramente non coincideranno.

Consulta la sezione Pickaxe

pertinente

Posso chiederti perché sei così preoccupato per la lunghezza della linea che si somma alla dimensione del file? Potresti risolvere un problema più difficile del necessario ...

Aha. Penso di averlo capito adesso.

Manca un comodo iPod (o qualsiasi altro tipo, del resto), non so se vuoi esattamente blocchi 4K, nel qual caso IO # read (4000) sarebbe tuo amico (4000 o 4096?) o se sei più felice di rompere la linea, nel qual caso qualcosa del genere dovrebbe funzionare:

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

Nota l'uso di readline di IO # per ottenere tutto il testo in una bava: farebbe anche #each o #each_line. Ho usato String # chomp! per garantire che qualunque cosa stia facendo il sistema operativo, i byte alla fine vengono rimossi, in modo che \ n o qualunque cosa possa essere forzata nell'output.

Suggerirei di utilizzare File # write, anziché #print o #puts per l'output, poiché questi ultimi hanno la tendenza a fornire sequenze di newline specifiche del sistema operativo.

Se sei davvero preoccupato per i caratteri multi-byte, considera di prendere le opzioni each_byte o unpack (C *) e String patch per scimmia, qualcosa del genere:

<*>

La versione di decompressione è circa 8 volte più veloce di quella di each_byte sulla mia macchina, tra l'altro.

Altri suggerimenti

Potresti provare IO # each_byte, ad esempio

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

Questo, ovviamente, non ti dà una linea alla volta. La tua migliore opzione è quella di passare attraverso il file tramite each_byte fino a quando non incontri \ r \ n . La classe IO offre un sacco di metodi di lettura di basso livello che potrebbero essere utili.

Potresti avere diversi problemi di sovrapposizione qui:

  1. Caratteri avanzamento riga \ r \ n vs. \ n (come da post precedente). Anche il carattere del file EOF (^ Z)?

  2. Definizione di " size " nell'affermazione del problema: intendi "quanti caratteri" (tenendo conto della codifica dei caratteri multi-byte) o vuoi dire "quanti byte"?

  3. Interazione della variabile globale $ KCODE (deprecata in ruby ??1.9. Vedi String # codifica e amici se hai meno di 1.9). Ci sono, ad esempio, caratteri accentati nel tuo file?

  4. La stringa di formato per #unpack . Penso che tu voglia C * se vuoi davvero contare i byte.

Nota anche l'esistenza di IO # each_line (solo così puoi buttare via il mentre ed essere un po 'più rubino-idiomatico; -)).

Il problema è che quando salvi un file di testo su Windows, le tue interruzioni di riga sono due caratteri (caratteri 13 e 10) e quindi 2 byte, quando lo salvi su Linux ne esiste solo 1 (carattere 10). Tuttavia, ruby ??riporta entrambi questi come un singolo carattere '\ n' - dice il carattere 10. Quel che è peggio, è che se sei su Linux con un file Windows, Ruby ti darà entrambi i caratteri.

Quindi, se sai che i tuoi file provengono sempre da file di testo di Windows ed eseguiti su Windows, ogni volta che ottieni un carattere di nuova riga puoi aggiungere 1 al tuo conteggio. Altrimenti è un paio di condizionali e una piccola macchina statale.

A proposito non c'è un 'personaggio' EOF.

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

Ecco una soluzione semplice, presumendo che il puntatore del file corrente sia impostato all'inizio di una riga nel file letto:

    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)

in questo esempio " file " è il file da cui stai leggendo. Per fare questo in un ciclo:

    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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top