Android escribir en disco no fiable – escrito file.length! = Expected.length

Tengo un método de escritura que escribirá un byte[] en el disco. En muy pocos dispositivos estoy corriendo en algunos problemas extraños donde el file.length() != byte[].length después de una operación de escritura exitosa.

Código y Problema

El código para escribir un archivo en el disco

 private static boolean writeByteFile(File file, byte[] byteData) throws IOException { if (!file.exists()) { boolean fileCreated = file.createNewFile(); if (!fileCreated) { return false; } } FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write(byteData); bos.flush(); fos.getFD().sync(); // sync to disk as recommended: http://android-developers.blogspot.com/2010/12/saving-data-safely.html fos.close(); if (file.length() != byteData.length) { final byte[] originalMD5Hash = md.digest(byteData); InputStream is = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer = new byte[4096]; while(bis.read(buffer) > -1) { md.update(buffer); } is.close(); final byte[] writtenFileMD5Hash = md.digest(); if(!Arrays.equals(originalMD5Hash, writtenFileMD5Hash)) { String message = String.format( "After an fsync, the file's length is not equal to the number of bytes we wrote!\npath=%s, expected=%d, actual=%d. >> " + "Original MD5 Hash: %s, written file MD5 hash: %s", file.getAbsolutePath(), byteData.length, file.length(), digestToHex(originalMD5Hash), digestToHex(writtenFileMD5Hash)); throw new GiantWtfException(message); } } return true; } 

Estoy corriendo en el if-statement donde comparar la longitud del archivo en algunos dispositivos. Un ejemplo de salida:

After an fsync, the file's length is not equal to the number of bytes we wrote! path=/mnt/sdcard/.folder/filename, expected=233510, actual=229376 >> Original MD5 Hash: f1d298c0484672c52d9c26d04a3a21dc, written file MD5 hash: ab30660bd2b476d9551c15b340207a8a

Actualmente veo este problema en 5 dispositivos como estoy poco a poco el desarrollo del código. Algunos datos del dispositivo:

Pregunta

¿Hay algo más que pueda hacer o mejorar?

Más estadísticas y observaciones

Versión actual del sistema

  • 2.3.5
  • 2.3.6

Modelo

  • N860 (LG)
  • GT-I9100G (Samsung)
  • GT-S5300 (Samsung)
  • GT-S7500 (Samsung)
  • LG-VS410PP (LG)

Otras estadísticas

En el análisis general de fallos (de Crittercism) siempre hay más espacio en disco libre en el momento en que ocurre el problema. Aún algunos (no todos) de los dispositivos han lanzado IOExceptions alrededor de no free disk space en un momento diferente.

Como siempre nunca he sido capaz de reproducir ese problema en cualquier teléfono de prueba que tengo.

Suposiciones / Observaciones:

Generalmente esperaría una IOException cuando el disco esté lleno. Todavía todas las excepciones que capto tienen menos bytes escritos entonces deberían tener.

Curiosamente, todo el número de bytes que realmente se han escrito en el disco es un múltiplo de 2^15 .

EDIT: He añadido una validación de la suma de comprobación MD5 que también falla y simplificado el código de ejemplo un poco para una mejor legibilidad. Aún falla en la naturaleza con diferentes hashes MD5.

file.length() , file.length() es el tamaño del archivo informado por el sistema operativo. Puede ser el espacio que ocupa el archivo en el disco o el número de bytes en el archivo.

Si el número devuelto es el tamaño en el disco, se relaciona con el número de clústeres que contienen el archivo. Por ejemplo, NTFS generalmente utiliza clústeres de 4 KB. Si guarda un documento de texto con 3 caracteres codificados en ASCII en un volumen con formato NTFS, el tamaño del archivo es 3 bytes, el tamaño del archivo en disco es 4096 bytes. En NTFS con un clúster de 4 KB todos los archivos son un múltiplo de 4096 bytes en el disco. Consulte http://en.wikipedia.org/wiki/Data_cluster para obtener más información.

Si el número devuelto es la longitud del archivo en bytes (de los metadatos del sistema de archivos subyacente), entonces debería tener una coincidencia exacta con el número de bytes que escribió, aunque no apostaría mi vida a él.

Android utiliza YAFFS o EXT4, si eso ayuda en absoluto.

Estoy totalmente de acuerdo con admirado, utilizar un hash. MD5 funcionaría muy bien. SHA o incluso CRC debe funcionar bien para esta tarea. Al escribir bytes en el disco, alimentar el flujo a su algoritmo hash también. Una vez que el archivo está escrito, leerlo de nuevo y alimentar a su hasher. Compare los resultados. Si desea asegurarse de que los datos están limpios, el tamaño del archivo no es suficiente.

  • ¿Cómo obtenemos los separadores de archivos utilizados por los diferentes sistemas de archivos?
  • Sistema de archivos de la tarjeta SD de Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.