Android FileOutputStream создает поврежденный файл - PullRequest
0 голосов
/ 23 марта 2011

У меня есть приложение, которое создает несколько файлов, используя байтовый массив, полученный из Socket InputStream. Файл отлично сохраняется, когда я просто сохраняю один файл, но если я сохраняю один файл, а затем повторно создаю экземпляр файлового потока и сохраняю другой файл, первый файл будет поврежден, а второй файл будет сохранен идеально. Я открыл два файла в текстовом редакторе, и кажется (примерно ...) первая 1/5 первого файла - это пробелы, но второй файл заполнен, и они оба имеют одинаковые свойства размера (9 128 731 байт). Следующий пример представляет собой дублирование senario, но с тем же результатом искажения:

FileOutputStream outStream;
outStream = new FileOutputStream("/mnt/sdcard/testmp3.mp3");
File file = new File("/mnt/sdcard/test.mp3");
FileInputStream inStream = new FileInputStream(file);
byte[] buffer = new byte[9128731];
inStream.read(buffer);
outStream.write(buffer, 0, buffer.length);
inStream.close();
outStream.flush();
outStream.close();
outStream = null;
outStream = new FileOutputStream("/mnt/sdcard/testmp32.mp3");
outStream.write(buffer, 0, buffer.length);
inStream.close();
outStream.flush();
outStream.close();
outStream = null;

Я попробовал этот EXACT-код в обычном Java-приложении, и оба файла были сохранены без проблем. Кто-нибудь знает, почему андроид делает это?

Любая помощь будет принята с благодарностью

Ответы [ 4 ]

5 голосов
/ 27 марта 2011

Как упоминал jtahlborn, вы не можете предполагать, что InputStream.read(byte[]) всегда будет читать столько байтов, сколько вы хотите. Также вам следует избегать использования такого большого байтового массива для одновременной записи. По крайней мере, без буферизации, вы можете что-то переполнить. Вы можете справиться с этими проблемами и сэкономить память, скопировав файл следующим образом:

File inFile = new File("/mnt/sdcard/test.mp3");
File outFile = new File("/mnt/sdcard/testmp3.mp3");
FileInputStream inStream = new FileInputStream(inFile);
FileOutputStream outStream = new FileOutputStream(outFile);
byte[] buffer = new byte[65536];
int len;
while ((len = inStream.read(buffer)) != -1) {
    outStream.write(buffer, 0, len);
}
inStream.close();
outStream.close();
1 голос
/ 23 марта 2011

Я вижу некоторые потенциальные проблемы, которые могут помочь вам начать отладку:

  1. Вы пишете в первый выходной поток перед тем, как закрыть входной поток. Это немного странно.

  2. Вы не можете точно измерить сходство / разницу между двумя двоичными файлами с помощью текстового редактора. Вам нужно посмотреть файлы в шестнадцатеричном редакторе (или лучше, Audacity )

  3. Я бы использовал BufferedOutputStream, как предлагается в документации для Android: out = new BufferedOutputStream(new FileOutputStream(file)); http://developer.android.com/reference/java/io/FileOutputStream.html

  4. В качестве метода отладки выведите содержимое buffer после первой записи. Кроме того, inStream.read() возвращает int. Я бы дополнительно сравнил это с buffer.length и убедился, что они одинаковые. В любом случае, я бы просто позвонил write(buffer) вместо write(buffer, 0, buffer.length), если у вас нет действительно веской причины.

-tjw

0 голосов
/ 27 марта 2011

Если у кого-то возникла такая же проблема, и она задалась вопросом, как ее исправить, я обнаружил, что проблема связана с моей SD-картой.Я купил SD-карту Kingston емкостью 32 ГБ и только вчера решил попробовать снова запустить тот же код, используя вместо этого внутреннее хранилище, и все работало отлично.Я также попробовал стандартную SD карту на 2 ГБ, с которой это шло, и это также работало отлично.Я рад, что мой код работает отлично, но немного расстроенный, я потратил 50 баксов на неисправную карту памяти.Спасибо за любой вклад.

0 голосов
/ 23 марта 2011

Вы предполагаете, что вызов read() будет читать столько байтов, сколько вы хотите.это неверно.этот метод свободен для чтения от 1 до байтов buffer.length.вот почему вы должны всегда использовать возвращаемое значение, чтобы определить, сколько байтов действительно было прочитано.Есть множество руководств по потокам, которые покажут вам, как правильно читать из потока Java (т.е. как полностью заполнить ваш буфер).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...