Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.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
包含超过4gb元素的Java阵列_Java_Arrays_64 Bit - Fatal编程技术网

包含超过4gb元素的Java阵列

包含超过4gb元素的Java阵列,java,arrays,64-bit,Java,Arrays,64 Bit,我有一个大文件,预计大约为12GB。我想在一台16 GB RAM的强大64位机器上将其全部加载到内存中,但我认为Java不支持这么大的字节数组: File f = new File(file); long size = f.length(); byte data[] = new byte[size]; // <- does not compile, not even on 64bit JVM javac提供: possible loss of precision found : lo

我有一个大文件,预计大约为12GB。我想在一台16 GB RAM的强大64位机器上将其全部加载到内存中,但我认为Java不支持这么大的字节数组:

File f = new File(file);
long size = f.length();
byte data[] = new byte[size]; // <- does not compile, not even on 64bit JVM
javac提供:

possible loss of precision
found   : long
required: int
         byte data[] = new byte[size];

Java数组索引的类型是
int
(4字节或32位),因此恐怕只能使用231位− 阵列中有1个或2147483647个插槽。我会将数据读入另一个数据结构,比如2D数组。

如果需要,可以将数据加载到数组数组中,数组的最大值为int.maxValue平方字节,甚至比最强大的机器在内存中保存的时间都要长。

我建议您定义一些“块”对象,每个对象都可以保存(比如)1Gb的数组,然后将它们组成一个数组。

Java数组使用整数作为索引。因此,最大数组大小为Integer.MAX_值

(不幸的是,我无法从Sun自己那里找到任何关于这一点的证据,但他们已经有了很多证据。)

我认为在此期间,最好的解决方案是制作一个2D阵列,即:

byte[][] data;

不,数组由
int
s索引(除了一些使用
short
s的JavaCard版本)。您需要将其分割成更小的数组,可能会使用一种类型来包装,这种类型可以为您提供
get(long)
set(long,byte)
,等等。对于如此大的数据段,您可能希望使用java.nio映射文件。

正如其他人所说,所有类型的java数组都由
int
索引,因此最大大小为231− 或2147483647个元素(约20亿)。这是由so指定的,因此切换到另一个操作系统或Java虚拟机不会有帮助


如果您想像上面建议的那样编写一个类来克服这个问题,那么您可以使用数组数组(为了更大的灵活性)或更改类型(a
long
是8字节,因此a
long[]
可以比a
byte[]
大8倍)

您可以考虑使用文件通道和MappedByteBuffer来对文件进行内存映射,

FileChannel fCh = new RandomAccessFile(file,"rw").getChannel();
long size = fCh.size();
ByteBuffer map = fCh.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
编辑:

好吧,我是个白痴,看起来ByteBuffer也只需要一个32位的索引,这很奇怪,因为FileChannel.map的size参数是一个长的。。。但是,如果您决定将文件分成多个2Gb块进行加载,我仍然建议您使用内存映射IO,因为它可以带来相当大的性能优势。基本上,您将所有IO责任转移到了操作系统内核上。

package com.deans.rtl.util;
package com.deans.rtl.util;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * 
 * @author william.deans@gmail.com
 *
 * Written to work with byte arrays requiring address space larger than 32 bits. 
 * 
 */

public class ByteArray64 {

    private final long CHUNK_SIZE = 1024*1024*1024; //1GiB

    long size;
    byte [][] data;

    public ByteArray64( long size ) {
        this.size = size;
        if( size == 0 ) {
            data = null;
        } else {
            int chunks = (int)(size/CHUNK_SIZE);
            int remainder = (int)(size - ((long)chunks)*CHUNK_SIZE);
            data = new byte[chunks+(remainder==0?0:1)][];
            for( int idx=chunks; --idx>=0; ) {
                data[idx] = new byte[(int)CHUNK_SIZE];
            }
            if( remainder != 0 ) {
                data[chunks] = new byte[remainder];
            }
        }
    }
    public byte get( long index ) {
        if( index<0 || index>=size ) {
            throw new IndexOutOfBoundsException("Error attempting to access data element "+index+".  Array is "+size+" elements long.");
        }
        int chunk = (int)(index/CHUNK_SIZE);
        int offset = (int)(index - (((long)chunk)*CHUNK_SIZE));
        return data[chunk][offset];
    }
    public void set( long index, byte b ) {
        if( index<0 || index>=size ) {
            throw new IndexOutOfBoundsException("Error attempting to access data element "+index+".  Array is "+size+" elements long.");
        }
        int chunk = (int)(index/CHUNK_SIZE);
        int offset = (int)(index - (((long)chunk)*CHUNK_SIZE));
        data[chunk][offset] = b;
    }
    /**
     * Simulates a single read which fills the entire array via several smaller reads.
     * 
     * @param fileInputStream
     * @throws IOException
     */
    public void read( FileInputStream fileInputStream ) throws IOException {
        if( size == 0 ) {
            return;
        }
        for( int idx=0; idx<data.length; idx++ ) {
            if( fileInputStream.read( data[idx] ) != data[idx].length ) {
                throw new IOException("short read");
            }
        }
    }
    public long size() {
        return size;
    }
}
}
导入java.io.FileInputStream; 导入java.io.IOException; /** * *@作者威廉。deans@gmail.com * *用于处理地址空间大于32位的字节数组。 * */ 公共类ByteArray 64{ 私有最终长块大小=1024*1024*1024;//1GiB 长尺寸; 字节[][]数据; 公共ByteArray64(长尺寸){ 这个。大小=大小; 如果(大小==0){ 数据=空; }否则{ int chunks=(int)(大小/块大小); 整数余数=(整数)(大小-((长)块)*块大小); 数据=新字节[块+(余数==0?0:1)][]; 对于(int idx=chunks;--idx>=0;){ 数据[idx]=新字节[(int)块大小]; } 如果(余数!=0){ 数据[块]=新字节[余数]; } } } 公共字节获取(长索引){ 如果(索引=大小){ 抛出新的IndexOutOfBoundsException(“尝试访问数据元素“+索引+”时出错。数组为“+大小+”元素长。”); } int chunk=(int)(索引/块大小); int偏移量=(int)(索引-((长)块)*块大小); 返回数据[块][偏移量]; } 公共无效集(长索引,字节b){ 如果(索引=大小){ 抛出新的IndexOutOfBoundsException(“尝试访问数据元素“+索引+”时出错。数组为“+大小+”元素长。”); } int chunk=(int)(索引/块大小); int偏移量=(int)(索引-((长)块)*块大小); 数据[块][偏移量]=b; } /** *模拟单个读取,通过几个较小的读取填充整个阵列。 * *@param fileInputStream *@抛出异常 */ 公共无效读取(FileInputStream FileInputStream)引发IOException{ 如果(大小==0){ 返回; }
对于(int idx=0;idxjava目前不支持包含超过2^32个元素的直接数组


希望在将来看到java的这一功能

我认为内存映射文件(使用CPU的虚拟内存硬件)的想法是正确的方法。除了MappedByteBuffer与本机阵列具有相同的2Gb限制之外。这个家伙声称用一个非常简单的MappedByteBuffer替代方案解决了这个问题:


不幸的是,当读取超过500Mb时,JVM崩溃。

不要用整数限制自己。MAX\u值

虽然这个问题在很多年前就被提出了,但是我想参与一个简单的例子,只使用JavaSE而不使用任何外部库

首先让我们假设这在理论上是不可能的,但实际上是可能的

新外观:如果数组是一个元素对象,那么拥有一个数组对象怎么样

下面是一个例子

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

/**
*
* @author Anosa
*/
 public class BigArray<t>{

private final static int ARRAY_LENGTH = 1000000;

public final long length;
private List<t[]> arrays;

public BigArray(long length, Class<t> glasss)
{
    this.length = length;
    arrays = new ArrayList<>();
    setupInnerArrays(glasss);

}

private void setupInnerArrays(Class<t> glasss)
{
    long numberOfArrays = length / ARRAY_LENGTH;
    long remender = length % ARRAY_LENGTH;
    /*
        we can use java 8 lambdas and streams:
        LongStream.range(0, numberOfArrays).
                        forEach(i ->
                        {
                            arrays.add((t[]) Array.newInstance(glasss, ARRAY_LENGTH));
                        });
     */

    for (int i = 0; i < numberOfArrays; i++)
    {
        arrays.add((t[]) Array.newInstance(glasss, ARRAY_LENGTH));
    }
    if (remender > 0)
    {
        //the remainer will 100% be less than the [ARRAY_LENGTH which is int ] so
        //no worries of casting (:
        arrays.add((t[]) Array.newInstance(glasss, (int) remender));
    }
}

public void put(t value, long index)
{
    if (index >= length || index < 0)
    {
        throw new IndexOutOfBoundsException("out of the reange of the array, your index must be in this range [0, " + length + "]");
    }
    int indexOfArray = (int) (index / ARRAY_LENGTH);
    int indexInArray = (int) (index - (indexOfArray * ARRAY_LENGTH));
    arrays.get(indexOfArray)[indexInArray] = value;

}

public t get(long index)
{
    if (index >= length || index < 0)
    {
        throw new IndexOutOfBoundsException("out of the reange of the array, your index must be in this range [0, " + length + "]");
    }
    int indexOfArray = (int) (index / ARRAY_LENGTH);
    int indexInArray = (int) (index - (indexOfArray * ARRAY_LENGTH));
    return arrays.get(indexOfArray)[indexInArray];
}
import java.lang.reflect.Array;
导入java.util.ArrayList;
导入java.util.List;
/**
*
*@作者Anosa
*/
公共类BigArray{
私有最终静态整数数组长度=1000000;
公共最终长度;
私有列表数组;
公共BigArray(长,类Glass)
{
这个长度=长度;
arrays=新的ArrayList();
阵列(玻璃);
}
专用空心阵列(玻璃类)
{
long NumberOfArray=长度/数组长度;
long Reminder=长度%数组长度;
/*
我们可以使用java 8 Lambda和streams:
长流射程
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

/**
*
* @author Anosa
*/
 public class BigArray<t>{

private final static int ARRAY_LENGTH = 1000000;

public final long length;
private List<t[]> arrays;

public BigArray(long length, Class<t> glasss)
{
    this.length = length;
    arrays = new ArrayList<>();
    setupInnerArrays(glasss);

}

private void setupInnerArrays(Class<t> glasss)
{
    long numberOfArrays = length / ARRAY_LENGTH;
    long remender = length % ARRAY_LENGTH;
    /*
        we can use java 8 lambdas and streams:
        LongStream.range(0, numberOfArrays).
                        forEach(i ->
                        {
                            arrays.add((t[]) Array.newInstance(glasss, ARRAY_LENGTH));
                        });
     */

    for (int i = 0; i < numberOfArrays; i++)
    {
        arrays.add((t[]) Array.newInstance(glasss, ARRAY_LENGTH));
    }
    if (remender > 0)
    {
        //the remainer will 100% be less than the [ARRAY_LENGTH which is int ] so
        //no worries of casting (:
        arrays.add((t[]) Array.newInstance(glasss, (int) remender));
    }
}

public void put(t value, long index)
{
    if (index >= length || index < 0)
    {
        throw new IndexOutOfBoundsException("out of the reange of the array, your index must be in this range [0, " + length + "]");
    }
    int indexOfArray = (int) (index / ARRAY_LENGTH);
    int indexInArray = (int) (index - (indexOfArray * ARRAY_LENGTH));
    arrays.get(indexOfArray)[indexInArray] = value;

}

public t get(long index)
{
    if (index >= length || index < 0)
    {
        throw new IndexOutOfBoundsException("out of the reange of the array, your index must be in this range [0, " + length + "]");
    }
    int indexOfArray = (int) (index / ARRAY_LENGTH);
    int indexInArray = (int) (index - (indexOfArray * ARRAY_LENGTH));
    return arrays.get(indexOfArray)[indexInArray];
}
public static void main(String[] args)
{
    long length = 60085147514l;
    BigArray<String> array = new BigArray<>(length, String.class);
    array.put("peace be upon you", 1);
    array.put("yes it worj", 1755);
    String text = array.get(1755);
    System.out.println(text + "  i am a string comming from an array ");

}