Search code examples
fileiobinaryfilesada

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.


Solution

  • 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.