In my humble oppinion, ruby wasn't made for such tasks. If you have to write to binary files a lot, it would be easiest to write some c functions for that and call them from ruby, which is quite easy using swig. I'm doing the same thing at the moment to write a raid simulator.
Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams? Collectives on Stack Overflow. Learn more. Write binary file in Ruby Ask Question.
Asked 12 years, 7 months ago. Active 6 years, 8 months ago. Viewed 51k times. Alex Kovshovik Alex Kovshovik 3, 4 4 gold badges 32 32 silver badges 36 36 bronze badges. Add a comment. Active Oldest Votes. AliciaBytes 7, 6 6 gold badges 35 35 silver badges 46 46 bronze badges. Pesto Pesto Yes, I think yours is the better answer for this particular question! This seems like what I want to do, but I still don't know how to do it.
If so, then we can read our files in a different way:. Calling advise method announces an intention to access data from the current file in a specific pattern. No major improvement here with using advise method.
We defined the chunk as bytes and we read our file chunk by chunk. Depending on the structure of your file this approach might be useful. First thing we can notice is that memory usage is way lower.
Main reason for that is that we read the file line by line or chunk by chunk and when the line is processed then it's garbage collected. We can see that by the size of the Objects Freed , it's quite high. We also tried to use here an advise method which we can tell how we want to process our file. More about IO advise can be found in the documentation.
Unfortunately, it didn't help us out here. In the example with reading by chunks IO read the memory usage will vary depending on the chunk size. If you find this way useful you can experiment with the chunk size. When using IO. There is also lazy method which returns a Enumerator::Lazy.
Lazy Enumerator has a few additional methods which enumerate values only on an as-needed basis. After figuring out how to encode the file header, the next step was to work on the DIB header, which includes some metadata about the image and how it should be displayed on the screen:.
The pack statement in the above code works in a very similar fashion as the code that writes out the BMP file header, with one exception: it needs to handle signed bit little endian integers.
The most interesting thing to note about this code is that each row of pixels ends up getting padded with some null characters. This is to ensure that each row of pixels is aligned on WORD boundaries 4 byte sequences.
This is a semi-arbitrary limitation that has to do with file storage constraints, but things like this are common in binary files. Sometimes calculations like this are provided for you in format specifications, other times you need to derive them yourself. Choosing to work with only 24bit per pixel images allowed me to skirt the question of how to generalize this computation to an arbitrary amount of bits per pixel.
While the padding code is definitely the most interesting aspect of the pixel array, there are a couple other details about this implementation worth discussing. It starts by matching the string with a regex to ensure that the input string is a valid sequence of 6 hexadecimal digits. If the validation succeeds, it then packs those values into a binary sequence, creating a string with three bytes in it.
The example below should make it clear what is going on here:. This pattern makes it possible for us to specify color values directly in hexadecimal strings and then convert them to their numeric value just before they get written to the file. With this last detail explained, you should now understand how to build a functional bitmap encoder for writing 24bit color images.
If seeing things broken out step by step caused you to lose a sense of the big picture, you can check out the source code for BMP::Writer. As you might expect, there is a nice symmetry between encoding and decoding binary files. To show just to what extent this is the case, I will walk you through the code which makes the following example run:.
The code below shows the methods which define the public interface:. This time, we still are working with an ordinary array of arrays to store the pixel data, and most of the work gets done as soon as the file is read in the constructor.
Because I decided to support only a single image type, most of the work of reading the headers is just for validation purposes. The key thing to notice about this code is that it reads from the file just the bytes it needs in order to parse the header.
This makes it possible to validate a very large file without loading much data into memory. Reading entire files into memory is rarely a good idea, and this is especially true when it comes to binary data because doing so will actually make your job harder rather than easier.
0コメント