Java: как обрезать массив байтов?

Итак, у меня есть код, который считывает определенное количество байтов из файла и возвращает результирующий массив байтов (это в основном используется для разбивки файлов на части для отправки по сети в виде (в конечном итоге) текста ascii в кодировке base64).

Он работает нормально, за исключением того, что когда генерируется последний фрагмент файла, он не является полным фрагментом. Таким образом, результирующий массив байтов не заполнен. Тем не менее, это постоянный размер, а это означает, что файл повторно собран, и к концу добавляется целая куча дополнительных данных (возможно, 0).

Как я могу сделать так, чтобы byte[] для последнего фрагмента файла действительно содержал только те данные, которые ему нужны? Код выглядит следующим образом:

 private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    raf.read(data);        
    raf.close();
    return data;
}

Таким образом, если chunkSize больше, чем оставшиеся байты в файле, возвращается полноразмерный byte[], но он заполнен только наполовину данными.


person Erin Drummond    schedule 17.12.2009    source источник


Ответы (3)


Вам нужно будет проверить возвращаемое значение RandomAccessFile.read(), чтобы определить количество прочитанных байтов. Если он отличается от chunkSize, вам придется скопировать массив в меньший и вернуть его.

private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    int bytesRead = raf.read(data);
    if (bytesRead != chunkSize) {
         byte[] smallerData = new byte[bytesRead];
         System.arraycopy(data, 0, smallerData, 0, bytesRead);
         data = smallerData;
    }
    raf.close();
    return data;
}
person Asaph    schedule 17.12.2009
comment
Используя Arrays.copyOf из поста выше вместо System.arraycopy (который вызвал исключение), это сработало отлично! Спасибо! - person Erin Drummond; 17.12.2009
comment
Исправил, у меня была опечатка в сравнении, нужно было использовать ==, а не =. - person notnoop; 17.12.2009
comment
@Erin Drummond: Какое исключение было выброшено System.arraycopy()? - person Asaph; 17.12.2009
comment
это было исключение IndexOutOfBoundsException iirc - person Erin Drummond; 18.12.2009
comment
@Erin Drummond: я понимаю, почему это происходит, и исправил свой ответ. Последним аргументом System.arraycopy() должно быть bytesRead, а не chunkSize. Да! Прости за это. Пожалуйста, попробуйте мой обновленный ответ и подтвердите, что он исправлен. Спасибо :) - person Asaph; 18.12.2009

RandomAccessFile.read() возвращает количество прочитанных байтов, поэтому при необходимости вы можете скопировать массив:

private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    int read = raf.read(data);
    raf.close();
    if (read == data.length) return data;
    else
      return Arrays.copyOf(data, read);
}

Если вы используете Java до версии 6, вам нужно реализовать Arrays.copyOf самостоятельно:

byte[] r = new byte[read];
System.arraycopy(data, 0, r, 0, read);
return r;
person notnoop    schedule 17.12.2009

Вы также можете использовать размер файла для расчета оставшегося количества байтов.

private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    int size = (int) Math.min(chunkSize, raf.length()-startByte);
    byte[] data = new byte[size];
    raf.read(data);
    // TODO check the value returned by read (throw Exception or loop)
    raf.close();
    return data;
}

Таким образом, вы не создаете дополнительный массив и вам не нужна копия. Вероятно, это не сильно повлияет.
Один важный момент IMO: проверьте значение, возвращаемое read, я думаю, что оно может быть меньше, чем оставшиеся байты. В javadoc указано:

Количество прочитанных байтов, самое большее, равно длине b

person user85421    schedule 18.12.2009