Копирование файлов в android с потоком ввода/вывода: хороший и плохой способ

Я сделал эти две процедуры для копирования файлов с помощью inputstream и outpustream. они совершенно одинаковы, но второй вызывает ArrayIndexOutOfBoundsException, в то время как первый работает безупречно, и я не знаю, почему:

    public void CopyStream(long size, InputStream is, OutputStream os) {
        final int buffer_size = 4096;
        byte[] bytes = new byte[buffer_size];
        try {
            int count,prog=0;
            while ((count = is.read(bytes)) != -1) {
                os.write(bytes, 0, count); //write buffer
                prog = prog + count;
                publishProgress(((long) prog) * 100 / size);
            }
            os.flush();
            is.close();
            os.close();
        } catch (Exception ex) {
            Log.e(TAG,"CS "+ex);
        }
    }

как вы можете догадаться, что процедура вызывается внутри AsyncTask, поэтому publishProgresss

    public void CopyStream(long size, InputStream is, OutputStream os) {
        final int buffer_size = 4096;
        try {
            byte[] bytes = new byte[buffer_size];
            for (int count=0,prog=0;count!=-1;) {
                count = is.read(bytes);
                os.write(bytes, 0, count);
                prog=prog+count;
                publishProgress(((long) prog)*100/size);
            }
            os.flush();
            is.close();
            os.close();
        } catch (Exception ex) {
            Log.e(TAG,"CS "+ex);
        }
    }

Кто-нибудь знает, почему работает, но нет? что мне не хватает?

Ответ 1

Проблема заключается в том, что ваш цикл цикла проверяет состояние после первого прогона. В основном ошибка возникает, когда она отлично считывает последний цикл, но в следующем цикле вызов is.read возвращает -1. Впоследствии вы пытаетесь вызвать os.write(байты, 0, -1); -1 - недопустимый индекс. Решение:

public void CopyStream(long size, InputStream is, OutputStream os) {
        final int buffer_size = 4096;
        try {
            byte[] bytes = new byte[buffer_size];
            for (int count=0,prog=0;count!=-1;) {
                count = is.read(bytes);
                if(count != -1) {
                  os.write(bytes, 0, count);
                  prog=prog+count;
                  publishProgress(((long) prog)*100/size);
                }
            }
            os.flush();
            is.close();
            os.close();
        } catch (Exception ex) {
            Log.e(TAG,"CS "+ex);
        }
    }

Но это гораздо более читаемо, как цикл while, поэтому я буду придерживаться этого. Для циклов следует использовать либо когда вы знаете количество циклов или циклов для каждого, где вы прокручиваете каждый отдельный элемент коллекции.

Ответ 2

Условие остановки цикла проверяется перед вызовом is.read(). Это позволяет ситуации, когда вы пытаетесь прочитать байты, получить результат в -1 и попытаться продолжить выполнение для кода цикла. Пока останавливается сразу после is.read() возвращает -1

Попробуйте следующее:

int count = is.read(bytes);
for (prog=0;count!=-1;) {
     os.write(bytes, 0, count);
     prog=prog+count;
     publishProgress(((long) prog)*100/size);
     count = is.read(bytes);
}

Ответ 3

private static final int BASE_BUFFER_SIZE = 4096;

public static void copyFile(InputStream inputStream, OutputStream outputStream)
        throws IOException {
    byte[] bytes = new byte[BASE_BUFFER_SIZE];
    int count;

    while ((count = inputStream.read(bytes)) != -1){
        outputStream.write(bytes, 0, count);
    }

    close(inputStream);
    close(outputStream);
}

public static void close(@Nullable OutputStream stream) {
    if (stream != null) {
        try {
            stream.flush();
        } catch (IOException ignored) {
        }
        try {
            stream.close();
        } catch (IOException ignored) {
        }
    }
}

public static void close(@Nullable InputStream stream) {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException ignored) {
        }
    }
}