Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何最有效地将文件(从Java读取)传递给本机方法?_Java_File_Performance_Io_Native - Fatal编程技术网

如何最有效地将文件(从Java读取)传递给本机方法?

如何最有效地将文件(从Java读取)传递给本机方法?,java,file,performance,io,native,Java,File,Performance,Io,Native,我有大约30000个文件(每个1MB),我想把它们放进一个本机方法中,它只需要一个字节数组和它的大小作为参数 我浏览了一些示例和基准(如),但它们都做了一些其他有趣的事情 基本上,我不关心文件的内容,我不想访问该文件或字节数组中的某些内容,也不想对其执行任何其他操作。我只想将一个文件放入一个本地方法中,该方法尽可能快地接受字节数组 目前我使用的是RandomAccessFile,但速度非常慢(10MB/s) 有类似的吗 byte[] readTheWholeFile(File file){ ..

我有大约30000个文件(每个1MB),我想把它们放进一个本机方法中,它只需要一个字节数组和它的大小作为参数

我浏览了一些示例和基准(如),但它们都做了一些其他有趣的事情

基本上,我不关心文件的内容,我不想访问该文件或字节数组中的某些内容,也不想对其执行任何其他操作。我只想将一个文件放入一个本地方法中,该方法尽可能快地接受字节数组

目前我使用的是RandomAccessFile,但速度非常慢(10MB/s)

有类似的吗

byte[] readTheWholeFile(File file){ ... }
我可以把它放进去

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

您有什么建议?

我不完全确定这是您要问的,但听起来您希望将文件内容作为字节数组有效地传递给本机方法


如果是这种情况,我建议您使用
BufferedInputStream
读取Java中的文件内容,并将其存储在通过分配的
ByteBuffer
中,这样就可以将其传递到JNI端并整体访问。现在,在本机方法中,您可以调用直接访问缓冲区。

下面是一个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;
   }
publicstaticbyte[]readFileFully(stringafilename)抛出IOException
{
字节[]retData=null;
文件输入文件=新文件(文件名);
如果(inputFile==null | | |!inputFile.exists()| | |!inputFile.canRead())
{
抛出新IOException(“无效文件:+aFileName”);
}
//读入文件数据
BufferedInputStream iStream=null;
尝试
{
iStream=new BufferedInputStream(new FileInputStream(inputFile));
int size=(int)inputFile.length();
retData=新字节[大小];
int bytes_read=0;
//在这里读东西
while(字节\读取<大小)
{
bytes_read+=iStream.read(retData,bytes_read,size-bytes_read);
}
}
最后
{
如果(iStream!=null)
{
尝试
{
iStream.close();
}
捕获(IOE异常)
{
}
}
inputFile=null;
}
返回数据;
}

使用常规数组可能效率低下,因为VM在将数组传递给本机代码时可能会复制该数组,并且在I/O期间也可能会使用中间内存

对于最快的IO,使用分配字节缓冲区。底层数组是“特殊的”,因为它不是常规JVM堆的一部分。本机代码和I/O可以直接访问阵列

要将数据读入缓冲区,请使用

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(randomAccessFile.length());
RandomAccessFile.getChannel().read(byteBuffer, 0);
要获取要传递给JNI的备份数组,请使用

byte[] byteArray = byteBuffer.array();
然后可以将该数组和文件长度传递给JNI

直接缓冲区很难创建,因为您的所有文件都是1MB(或大约1MB),您应该能够在多个文件上重用同一缓冲区


希望这有帮助

您不能在本机代码本身中执行i/o有什么原因吗?由于内存模型不同,将数据从Java传递到本机非常昂贵。不,很遗憾,这是不可能的。我希望有一种方法可以让JVM看到,放入本机方法的字节数组不会在Java代码中再次使用,而只是向本机代码提供内存范围,而不是开始复制它…没有办法在Java中获得内存范围感谢您的答案mdma!我只是想知道,我怎样才能确保array()能正常工作?Javadoc说“在调用这个方法之前调用hasArray方法,以确保这个缓冲区有一个可访问的后备数组。”而allocateDirect()告诉我“它是否有后备数组是未指定的。”我想知道这是否会起作用?这是一些更依赖于平台的特性的问题,它依赖于VM。您可以捕获array()抛出的exoption,并使用ByteBuffer.get(byte[])作为回退获取数组。如果您确实直接访问所有虚拟机,那么可以编写一个小型JNI存根方法,该方法接受direct ByteBuffer实例,并调用GetDirectByteBufferAddress,然后将其转发到原始JNI方法。如果ByteBuffer必须将数据复制一次到一个新数组中,那么它会很快-这些都是优化的方法,比将文件逐段读入字节[]要快得多。另外一点可能有助于提高性能-使用多线程。即使您的应用程序将被I/O绑定,I/O也会阻止等待数据(例如,非连续文件)。让多个线程同时读取不同的文件会给您带来加速,特别是使用异步I/O。ForkJoin框架(JSR 166)对于这类工作非常有用,而且非常容易使用:将文件操作重构为一项任务。为要处理的每个文件创建一个任务,并将它们全部放入任务队列中。然后,任务队列以指定的并行级别运行这些任务。