更新を続けるため、サイズが不明なバイト配列を宣言していますが、無限サイズ/可変サイズのバイト配列を宣言するにはどうすればよいですか?
10 に答える
無限のメモリが必要になるため、無限のサイズの配列を宣言することはできません。さらに、すべての割り当て呼び出しは、無限の数量ではなく、数値を処理します。
必要に応じてサイズを変更するバイトバッファを割り当てることができます。最も簡単な選択はByteArrayOutputStream
です。
ByteBuffer
バッファの操作を簡単にするAPIがありますが、サイズ変更機能を自分で作成する必要があります。最も簡単な方法は、新しい、より大きな配列を割り当て、古いコンテンツをコピーして、新しいバッファを古いものと交換することです。
他の回答はList<Byte>
、ある種のを使用して言及しています。new Byte()
多数のオブジェクトを作成すると、メモリ消費量が大幅に増加する可能性 があることに注意してください。Byte.valueOf
この問題を回避しますが、コード全体で一貫して使用されるようにする必要があります。このリストを多くの場所で使用する場合は、List
すべての要素をインターンする単純なデコレータを作成することを検討してください。例えば:
public class InterningList extends AbstractList<Byte>
{
...
@Override
public boolean add(Byte b) {
return super.add(Byte.valueOf(b));
}
...
}
これは完全な(またはテストされた)例ではなく、最初から何かです...
Javaの配列は動的ではありません。代わりにリストを使用できます。
List<Byte> list = new ArrayList<Byte>();
自動ボクシング機能により、バイトオブジェクトまたはプリミティブバイトのいずれかをこのリストに自由に追加できます。
commons.io.IOUtils
さまざまな長さのバイト配列を定義するには、次のような手動の長さを割り当てる代わりに、apacheライブラリを使用します。
byte[] b=new byte[50];
入力ストリームを関数に渡すことができます。IOUtils
この関数は、この入力ストリームで読み取り関数を実行するため、バイト配列は必要に応じて正確なバイト長になります。元。
byte[] b = IOUtils.toByteArray(inpustream);
混沌..
ByteArrayOutputStreamは、動的バイト配列への書き込みを可能にします。ただし、削除、置換、挿入などの方法は使用できません。バイト配列を抽出してから直接操作する必要があります。
明らかな解決策は、ArrayListを使用することです。
ただし、これは、パフォーマンスが必要な場合やメモリに制約がある場合は、実際にはバイトではなくバイト(つまり、オブジェクト)を格納するため、悪い解決策です。
実際のアプリケーションの場合、答えは簡単です。必要に応じてバイト配列を拡張するメソッドを使用して、バイト配列を自分で管理する必要があります。必要に応じて、特定のクラスに埋め込むことができます。
public class AlmostInfiniteByteArray {
private byte[] array;
private int size;
public AlmostInfiniteByteArray(int cap) {
array = new byte[cap];
size = 0;
}
public int get(int pos) {
if (pos>=size) throw new ArrayIndexOutOfBoundsException();
return array[pos];
}
public void set(int pos, byte val) {
if (pos>=size) {
if (pos>=array.length) {
byte[] newarray = new byte[(pos+1)*5/4];
System.arraycopy(array, 0, newarray, 0, size);
array = newarray;
}
size = pos+1;
}
array[pos] = val;
}
}
最善の策は、ArrayListを使用することです。塗りつぶすとサイズが変更されます。
List<Byte> array = new ArrayList<Byte>();
ArrayListの初期容量は10です。ArrayList(5000)で変更できます。ArrayListは、必要に応じてサイズを2倍にします(新しい配列を作成し、古い配列を新しい配列にコピーします)。
他の人の答えを少し微調整します。
配列を管理するためのLargeByteArrayクラスを作成します。getメソッドやsetメソッドなど、必要なものは何でもあります。
舞台裏では、そのクラスはlongを使用して現在の長さを保持し、ArrayListを使用して配列の内容を格納します。
バイト[8192]またはバイト[16384]配列をArrayListに格納することを選択します。これにより、無駄なサイズの点で妥当なトレードオフが得られ、サイズ変更の必要性が減ります。
配列を「スパース」にすることもできます。つまり、そのボックスにゼロ以外の値が格納されている場合にのみ、list.get(index / 8192)エントリを割り当てます。
このような構造は、場合によっては大幅に多くのストレージを提供できます。
使用できるもう1つの戦略は、書き込み後にbyte []ボックスを圧縮し、読み取り前に解凍することです(読み取りには、LRUキャッシュを使用します)。これにより、使用可能なRAMの2倍以上を格納できます...これは圧縮戦略によって異なります。
その後、いくつかのボックスをディスクにページングするのを見ることができます...
それは私があなたを得ることができる限り無限の配列に近いです;-)
Prashantがすでに言ったように、IOUtilsを断片から利用することができます。
これがタスクを解決できる小さな部分です(IOUtils.toByteArrayが必要になります):
public class IOUtils {
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(input, output);
return output.toByteArray();
}
public static int copy(InputStream input, OutputStream output)
throws IOException {
long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
public static long copyLarge(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
}