Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a binary file entirely and quickly in Ada?

I would like to read the content of a binary file of several MB and store it into a buffer. Here's my function prototype (I can change it if needed):

procedure GET_BIN_CONTENT_FROM_PATH(PATH    : in UNBOUNDED_STRING;
                                    CONTENT : out UNBOUNDED_STRING);

Until now I've tried two methods, both using the Direct_IO package. In the first method, I was reading the file character by character; it worked, but it was awfully slow. In order to speed up the process, I tried to read the file MB by MB:

procedure GET_BIN_CONTENT_FROM_PATH (PATH    : in UNBOUNDED_STRING;
                                     CONTENT : out UNBOUNDED_STRING) is

   BIN_SIZE_LIMIT : constant NATURAL := 1000000;
   subtype FILE_STRING is STRING (1 .. BIN_SIZE_LIMIT);
   package FILE_STRING_IO is new ADA.DIRECT_IO (FILE_STRING);
   FILE : FILE_STRING_IO.FILE_TYPE;
   BUFFER : FILE_STRING;

begin
   FILE_STRING_IO.OPEN (FILE, MODE => FILE_STRING_IO.IN_FILE,
                        NAME => TO_STRING (C_BASE_DIR & PATH));
   while not FILE_STRING_IO.END_OF_FILE (FILE) loop
      FILE_STRING_IO.READ (FILE, ITEM => BUFFER);
      APPEND (CONTENT, BUFFER);
   end loop;
   FILE_STRING_IO.CLOSE (FILE);
end GET_BIN_CONTENT_FROM_PATH;

Unfortunately, it seems that the READ operation won't happen if there is less than 1MB remaining in the file. As a result, big files (>1MB) get truncated, and little ones are not read at all. It's especially visible when working on images.

So, my question is: What's the correct method to read a binary file both quickly and entirely?

Thanks in advance.

like image 416
tvuillemin Avatar asked Dec 09 '22 18:12

tvuillemin


2 Answers

Make the Bin_Size equal to Ada.Directories.Size(my_file), and read it in one go.

If it's too big for stack allocation (you'll get Storage_Error) allocate it with New, and use the rename trick

my_image : bin_array renames my_image_ptr.all;

so that nothing else need know...
But if it's only a few MB, that won't be necessary.

like image 126
user_1818839 Avatar answered Dec 11 '22 08:12

user_1818839


Ada.Streams.Stream_IO.Read reads into a Stream_Element_Array and tells you the last element read; if the array isn't filled (because you've reached the end of file), Last will be less than Item'Last.

A purist will note that Ada.Streams.Stream_Element'Size may not be the same as Character'Size, but for any normal processor chip it will be, so you can do unchecked conversion between the used part of the Stream_Element_Array and a String of the same size before appending to your Content.

like image 27
Simon Wright Avatar answered Dec 11 '22 09:12

Simon Wright