java.io.File.length() greater than 0 when actual file is 0 bytes

Destiny Faith :

What:

My Android application is compressing a directory on rooted Android Devices (API 25+) and writing the zip to a removable USB stick.

Problem:

Java is telling my that the file is 97,993 bytes but when I take the USB stick out of the Android Device and plug it into my mac, mac is saying it's 0 bytes.

Code:

/// Where is the directory that we're compressing onto the USB stick?
File dir = new File(Environment.getExternalStorageDirectory(), "logs");
if (!dir.exists() || !dir.isDirectory()) throw new IOException("Invalid directory.");

/// Where on the USB stick is the logs.zip going to go?
File zip = new File("/storage/FD91-1317/logs.zip");

/// Delete the file if it already exists then recreate it 
if (zip.exists() && !zip.delete()) throw new IOException("Failed to create zip file.");
zip.createNewFile();

/// Using try {} to manage our streams
try (FileOutputStream fileOutputStream = new FileOutputStream(zip); ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream)) {
    /// Get the list of files to enumerate through
    File[] files = dir.listFiles();

    // Enumerate through each file to be compressed
    for (File file : files) {
        /// If somehow a file was deleted throw an exception
        if (!file.exists()) throw new FileNotFoundException(file.getPath());

        /// Create the new zip entry
        zipOutputStream.putNextEntry(new ZipEntry(file.getName()));

        /// Copy the file into the zip
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            IOUtils.copy(fileInputStream, zipOutputStream);
        }

        /// Close the zip entry
        zipOutputStream.closeEntry();
    }
}

/// Validate that the zip has been created successfully 
if (zip.length() == 0) throw new IOException("Zip failed to be created!!!!");
Log.v("logs", String.format("Logs collected: %s", zip.length());

More Info:

  • My application is running as a system app in the /system/priv-app/ directory
  • My application has the android.permission.WRITE_MEDIA_STORAGE permission
  • The zip file on the USB stick is only 0 bytes when plugged into the mac, if I remove the USB stick within 5-10 seconds after Log.v(...) is called. If I wait longer than 10 seconds it'll always have bytes.
  • Log.v(...) also is logging Logs collected: 97993
  • org.apache.commons.io.FileUtils.readFileToByteArray(zip) is also returning a byte array with the length of 97993 and the byte array 100% has data in it and isn't empty.
  • ls -l /storage/FD91-1317 is also saying that logs.zip is 97993 bytes.

Closing:

I've tried literally everything I can think of at this point but still can't figure out why Java is saying that the zip contains data but when plugged into my mac it's saying the file is 0 bytes. Windows is telling me the same thing. The only thing I know for a fact is that if I wait more than 10 seconds before removing the USB from my Android device, then this problem will not occur but I worry that depending on the size of the zip, that might not be enough time in all cases. To my knowledge, once you write to a stream and close it, it should be 100% completed.

Destiny Faith :

In order to fix the issue, I had to run fileOutputStream.getFD().sync();
If anyone is wondering why running that had fixed it, here is a snippet from Java's docs to explain what sync(); does.

enter image description here

See: https://docs.oracle.com/javase/7/docs/api/java/io/FileDescriptor.html#sync() for more details.


Thanks so much to @CommonsWare for assisting!

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=422262&siteId=1