Ruby:Länge einer Zeile einer Datei in bytes?
Frage
Ich Schreibe dieses kleine "HelloWorld" als follow-up zu diese und die zahlen addieren sich nicht
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}"
Das Ergebnis ist nicht das gleiche wie die Größe der Datei.Ich glaube, ich muss nur wissen, was format
Ich Notwendigkeit, plug in...oder vielleicht habe ich den Punkt verpasst ganz. Wie kann ich Messen die Größe der Datei Zeile für Zeile?
Hinweis:Ich bin auf Windows und die Datei codiert ist als Typ ANSI.
Edit: Dies ergibt die gleichen Ergebnisse!
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}"
also wer kann jetzt helfen...
Lösung
IO - #bekommt funktioniert genauso wie wenn Sie waren erfassen Eingang von der Befehlszeile aus:die "Enter" - ist nicht geschickt, als Teil des input;es ist auch bestanden, wenn #wird aufgefordert, eine Datei oder eine andere Unterklasse von IO -, also die zahlen sind definitiv nicht zu passen.
Siehe die entsprechenden Spitzhacke Abschnitt
Darf ich Fragen, warum Sie so besorgt sind die Leitungslängen addieren, die Größe der Datei?Sie können der Lösung schwieriger Probleme als nötig ist...
Aha.Ich denke, ich bekomme es jetzt.
Fehlt eine handliche iPod (oder jede andere Sorte, für diese Angelegenheit), ich weiß nicht, ob Sie genau möchten 4K-Blöcken, in welchem Fall IO#Lesen(4000) würde dein Freund sein (4000 4096?) oder wenn Sie glücklicher sind, brechen durch die Linie, in dem Fall so etwas sollte funktionieren:
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
Beachten Sie die Verwendung von IO#readlines um den gesamten text in einem slurp:#oder #each_line nicht genauso gut wäre.Ich verwendete String#chomp!um sicherzustellen, dass alles, was das Betriebssystem ist dabei, die byts am Ende wieder entfernt, so dass oder was auch immer, gezwungen werden in die Ausgabe.
Ich würde vorschlagen, mit Datei#schreiben, eher als #print oder #setzt für den Ausgang, als die letzteren haben eine Tendenz, zu liefern, OS-spezifische newline-Sequenzen.
Wenn Sie wirklich besorgt über die multi-byte-Zeichen, in Betracht ziehen, die each_byte oder entpacken(C*), Optionen und monkey-patching String, so etwas wie dieses:
class String
def size_in_bytes
self.unpack("C*").size
end
end
Entpacken-version ist etwa 8-mal schneller als die each_byte auf meiner Maschine, btw.
Andere Tipps
Sie könnten versuchen, IO # each_byte, z.
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}"
Das ist natürlich, Sie zu einer Zeit, eine Linie nicht geben. Ihre beste Möglichkeit dafür ist wahrscheinlich durch die Datei über each_byte
gehen, bis Sie \r\n
begegnen. Die IO-Klasse bietet eine Reihe von ziemlich Low-Level-Lesemethoden, die hilfreich sein könnten.
Sie haben möglicherweise mehrere überlappende Probleme hier:
-
Linefeeds
\r\n
vs.\n
(wie pro Ihre früheren Post). Auch EOF-Datei Zeichen (^ Z)? -
Definition von „Größe“ in der Problemstellung: meinst du „wie viele Zeichen“ (unter Berücksichtigung der Multi-Byte-Zeichenkodierungen) oder meinst du „wie viele Bytes“
? li> -
Die Interaktion der
$KCODE
globalen Variable (veraltet in Ruby 1.9. SieheString#encoding
und Freunde, wenn Sie unter 1.9 laufen lassen). Gibt es zum Beispiel Zeichen mit Akzent in der Datei? -
Ihr Format-String für
#unpack
. Ich glaube, Sie wollen hierC*
wenn Sie wirklich Bytes wollen zählen.
Beachten Sie auch die Existenz von IO#each_line
(nur so können Sie die while
wegwerfen kann und sein ein wenig mehr rubin idiomatische; -)).
Das Problem ist, dass, wenn Sie eine Textdatei auf Windows speichern, Ihre Zeilenumbrüche sind zwei Zeichen (Zeichen 13 und 10) und damit 2 Bytes, wenn Sie es auf Linux sparen gibt es nur 1 (Zeichen 10). Allerdings Rubin berichtet sowohl diese als ein einzelnes Zeichen ‚\ n‘ -. Es sagt Charakter 10. Was noch schlimmer ist, ist, dass, wenn Sie auf Linux mit einer Windows-Datei sind, rubin Ihnen beiden Zeichen geben
Also, wenn Sie auf wissen , dass Ihre Dateien immer aus den Fenstern Textdateien und ausgeführt werden, kommen auf Fenster, jedes Mal wenn ein Newline-Zeichen erhalten Sie 1 zu Ihrer Zählung hinzufügen können. Ansonsten ist es ein paar conditionals und eine wenig Zustandsmaschine.
BTW es gibt keinen 'Charakter' EOF.
f = File.new("log.txt")
begin
while (line = f.readline)
line.chomp
puts line.length
end
rescue EOFError
f.close
end
Hier ist eine einfache Lösung, vorausgesetzt, dass die aktuellen Dateizeiger auf den Anfang einer Zeile in der Lesedatei festgelegt ist:
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 diesem Beispiel „Datei“ die Datei, von der Sie gerade lesen. Um dies zu tun in einer Schleife:
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