Как наиболее эффективно передать файл (чтение из Java) нативному методу? - PullRequest
4 голосов
/ 26 апреля 2010

у меня ок. 30000 файлов (1 МБ каждый), которые я хочу поместить в собственный метод, для которого требуется только байтовый массив и размер его в качестве аргументов.

Я просмотрел некоторые примеры и тесты (например, http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly), но все они делают некоторые другие причудливые вещи.

По сути, меня не волнует содержимое файла, я не хочу получать доступ к чему-либо в этом файле или байтовом массиве или делать с ним что-то еще. Я просто хочу поместить файл в собственный метод, который принимает байтовый массив как можно быстрее.

В данный момент я использую RandomAccessFile, но это ужасно медленно (10 МБ / с).

Есть что-нибудь подобное

byte[] readTheWholeFile(File file){ ... }

который я мог бы положить в

native void fancyCMethod(readTheWholeFile(myFile), myFile.length())

Что бы вы предложили?

Ответы [ 3 ]

1 голос
/ 27 апреля 2010

Использование обычных массивов может быть неэффективным, так как виртуальная машина может копировать массив при передаче его в собственный код, а также может использовать промежуточную память во время ввода-вывода.

Для самого быстрого ввода-вывода используйте ByteBuffer.allocateDirect для выделения байтового буфера. Базовый массив является «особенным» в том смысле, что он не является частью обычной кучи JVM. Собственный код и ввод / вывод могут обращаться к массиву напрямую.

Чтобы прочитать данные в буфер, используйте

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(randomAccessFile.length());
RandomAccessFile.getChannel().read(byteBuffer, 0);

Чтобы получить массив поддержки для передачи в JNI, используйте

byte[] byteArray = byteBuffer.array();

Затем вы можете передать этот массив и длину файла в JNI.

Прямые буферы создавать очень тяжело, так как все ваши файлы занимают 1 МБ (или около того), вы должны иметь возможность повторно использовать один и тот же буфер в нескольких файлах.

Надеюсь, это поможет!

1 голос
/ 27 апреля 2010

Я не совсем уверен, что это то, о чем вы спрашиваете, но звучит так, будто вы хотите эффективно передать содержимое файла в виде байтового массива нативному методу.

Если это так, я предлагаю вам прочитать содержимое файла в Java с помощью BufferedInputStream и сохранить его в ByteBuffer, который был выделен с помощью ByteBuffer#allocateDirect, таким образом, его можно передать на стороне JNI и доступ в целом. Теперь в нативном методе вы можете вызвать GetDirectByteBufferAddress для прямого доступа к буферу.

0 голосов
/ 27 апреля 2010

Вот пример readFileFully, который вы можете реализовать

   public static byte[] readFileFully(String aFileName) throws IOException
   {
      byte[] retData = null;

      File inputFile = new File(aFileName);
      if (inputFile == null || !inputFile.exists() || !inputFile.canRead())
      {
         throw new IOException("INVALID FILE : " + aFileName);
      }

      // Read in the file data
      BufferedInputStream iStream = null;
      try
      {
         iStream = new BufferedInputStream(new FileInputStream(inputFile));
         int size = (int)inputFile.length();
         retData = new byte[size];
         int bytes_read = 0;

         // read stuff in here
         while (bytes_read < size)
         {
            bytes_read += iStream.read(retData,bytes_read,size - bytes_read);
         }
      }
      finally
      {
         if (iStream != null)
         {
            try
            {
               iStream.close();
            }
            catch(IOException e)
            {
            }
         }
         inputFile = null;
      }
      return retData;
   }
...