How to navigate in a file?

Hi,

I would like to open a binary file and read its contents.
The opening is no problem, but if I wanted to jump to a specific byte,
how would I do that ? Also, how would I read this specific byte ? I have
some code reading the byte, but it quite ugly. Is there something like
DATA.readbyte(position) ?

greetings, BXS

What you’re looking for is File#seek(offset). For instance:

foo.rb(main):001:0> # Create a binary file where the byte at position N = N
foo.rb(main):002:0* File.open(“binfile”, “wb”) do
foo.rb(main):003:1* |f|
foo.rb(main):004:1* 256.times do
foo.rb(main):005:2* |b|
foo.rb(main):006:2* f.write(b.chr)
foo.rb(main):007:2> end
foo.rb(main):008:1> end
=> 256
foo.rb(main):009:0>
foo.rb(main):010:0* # Seek to position 128 and read the byte there
foo.rb(main):011:0* File.open(“binfile”, “rb”) do
foo.rb(main):012:1* |f|
foo.rb(main):013:1* f.seek(128)
foo.rb(main):014:1> b = f.getc
foo.rb(main):015:1> puts b
foo.rb(main):016:1> end
128
=> nil
foo.rb(main):017:0>

-Mark

···

On Fri, Dec 05, 2003 at 01:58:22AM +0100, Boris BXS Schulz wrote:

Hi,

I would like to open a binary file and read its contents.
The opening is no problem, but if I wanted to jump to a specific byte,
how would I do that ? Also, how would I read this specific byte ? I have
some code reading the byte, but it quite ugly. Is there something like
DATA.readbyte(position) ?

~/eg/ruby > cat byte.rb

require ‘mmap’ # guy’s package from the RAA - get it!

binary = ‘bin.dat’

create a binary file

open(binary, ‘wb’) do |f|
bytes = [1 << 2, 1 << 1].pack ‘cc’
f.write bytes
end

memory map it (man mmap)

mmap = Mmap.new binary, ‘r’
byte_a, byte_b = mmap[0], mmap[1]

print byte_a
print byte_b
puts

~/eg/ruby > ruby byte.rb
42

in addition to being really easy to use, this package is really fast.

-a

···

On Fri, 5 Dec 2003, Boris “BXS” Schulz wrote:

Date: Fri, 05 Dec 2003 01:58:22 +0100
From: Boris “BXS” Schulz bxs@hadiko.de
Newsgroups: comp.lang.ruby
Subject: how to navigate in a file ?

Hi,

I would like to open a binary file and read its contents.
The opening is no problem, but if I wanted to jump to a specific byte,
how would I do that ? Also, how would I read this specific byte ? I have
some code reading the byte, but it quite ugly. Is there something like
DATA.readbyte(position) ?

greetings, BXS

ATTN: please update your address books with address below!

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
STP :: Solar-Terrestrial Physics Data | NCEI
NGDC :: http://www.ngdc.noaa.gov/
NESDIS :: http://www.nesdis.noaa.gov/
NOAA :: http://www.noaa.gov/
US DOC :: http://www.commerce.gov/

The difference between art and science is that science is what we
understand well enough to explain to a computer.
Art is everything else.
– Donald Knuth, “Discover”

/bin/sh -c ‘for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done’
===============================================================================

“Mark J. Reed” markjreed@mail.com schrieb im Newsbeitrag
news:20031205025328.GA10409@mulan.thereeds.org

Hi,

I would like to open a binary file and read its contents.
The opening is no problem, but if I wanted to jump to a specific byte,
how would I do that ? Also, how would I read this specific byte ? I
have
some code reading the byte, but it quite ugly. Is there something like
DATA.readbyte(position) ?

What you’re looking for is File#seek(offset). For instance:

foo.rb(main):001:0> # Create a binary file where the byte at position N
= N
foo.rb(main):002:0* File.open(“binfile”, “wb”) do
foo.rb(main):003:1* |f|
foo.rb(main):004:1* 256.times do
foo.rb(main):005:2* |b|
foo.rb(main):006:2* f.write(b.chr)
foo.rb(main):007:2> end
foo.rb(main):008:1> end
=> 256
foo.rb(main):009:0>
foo.rb(main):010:0* # Seek to position 128 and read the byte there
foo.rb(main):011:0* File.open(“binfile”, “rb”) do
foo.rb(main):012:1* |f|
foo.rb(main):013:1* f.seek(128)
foo.rb(main):014:1> b = f.getc
foo.rb(main):015:1> puts b
foo.rb(main):016:1> end
128
=> nil
foo.rb(main):017:0>

Note that for reading and writing “r+b” is the appropriate open mode.

File.open(“io-test.txt”, “r+b”) do |io|
puts “read”
io.seek(0)

while ( b = io.read(1) )
printf “%4d 0x%02x %s\n”, io.tell, b[0], b.inspect
end

puts “write”
io.seek(0)

io.write( “xxx” )

puts “read again”
io.seek(0)

while ( b = io.read(1) )
printf “%4d 0x%02x %s\n”, io.tell, b[0], b.inspect
end
end

Regards

robert
···

On Fri, Dec 05, 2003 at 01:58:22AM +0100, Boris BXS Schulz wrote:

[mmap]

sounds like a good idea, except, I am a WindowsXP user, and it says
something about beeing only for unix on
http://raa.ruby-lang.org/list.rhtml?name=mmap
So i’ll have to stick with the other guys advice.

Thanks to all of you, BXS

Hi,

[mmap]

sounds like a good idea, except, I am a WindowsXP user, and it says
something about beeing only for unix on
http://raa.ruby-lang.org/list.rhtml?name=mmap
So i’ll have to stick with the other guys advice.

By the way, if you like, you can define operators for
File class, like:

class File
def
seek(pos)
read(1)
end
def =(pos, str)
seek(pos)
write(str)
end
end

Then you can:

f = File.open(“zzz.wav”, “r+b”)
=> #<File:zzz.wav>

wav files start out with ‘RIFF’

f[0]
=> “R”
f[1]
=> “I”
f[2]
=> “F”
f[3]
=> “F”

let’s write a ‘Z’ in place of the ‘R’

f[0] = “Z”
=> “Z”

f[0]
=> “Z”
f[1]
=> “I”
f[2]
=> “F”

let’s write the string ‘ZOOM’ in place of the ‘RIFF’

f[0] = “ZOOM”
=> “ZOOM”

f[0]
=> “Z”
f[1]
=> “O”
f[2]
=> “O”
f[3]
=> “M”

Hope this helps,

Bill

···

From: “Boris “BXS” Schulz” bxs@hadiko.de

Hi,

thanks, I was trying to handle MP3s, and not WAVs, but that should
really help :slight_smile:
I will try all of this after dinner.

greetings, BXS