CSV file exports to local storage but appears empty when saved to Google Drive using ACTION_CREATE_DOCUMENT

Google Drive File Creation Issue

I’m working on an Android app that generates CSV reports. The app uses ACTION_CREATE_DOCUMENT intent to let users choose where to save files. Everything worked perfectly until recently when I discovered a weird problem.

When users save files to their device’s Downloads folder, the CSV file gets created properly with all the data. But when they pick Google Drive as the destination, the file shows up as completely empty (0 bytes) even though my code runs without any errors.

I’ve tested this on multiple devices running Android 7 and 8, and they all have the same issue. Strangely, an older Android 5 device works fine with Google Drive. The URI I receive looks correct (content://com.google.android.apps.docs.storage/document/acc%3...).

Has anyone encountered this before? What could be causing Google Drive files to stay empty while local storage works fine?

Here’s my simplified test code:

public class TestActivity extends AppCompatActivity {

    private static final int SAVE_FILE_REQUEST = 42;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK) return;

        if (requestCode == SAVE_FILE_REQUEST && data != null) {
            Uri fileUri = data.getData();
            if (fileUri != null) {
                new WriteFileTask(this).execute(fileUri);
            }
        }
    }

    public void exportData(View view) {
        Intent createIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        createIntent.addCategory(Intent.CATEGORY_OPENABLE);
        createIntent.setType("text/csv");
        createIntent.putExtra(Intent.EXTRA_TITLE, "report.csv");
        startActivityForResult(createIntent, SAVE_FILE_REQUEST);
    }

    private static class WriteFileTask extends AsyncTask<Uri, Void, Boolean> {
        private final WeakReference<Context> contextRef;

        WriteFileTask(Context context) {
            contextRef = new WeakReference<>(context);
        }

        @Override
        protected Boolean doInBackground(Uri... params) {
            Uri targetUri = params[0];
            Context ctx = contextRef.get();

            if (ctx == null) return false;

            String csvContent = "name,value\ntest,123\nsample,456\n";
            boolean writeSuccess = false;

            try {
                ParcelFileDescriptor descriptor = ctx.getContentResolver().openFileDescriptor(targetUri, "w");
                if (descriptor != null) {
                    FileOutputStream outputStream = new FileOutputStream(descriptor.getFileDescriptor());
                    outputStream.write(csvContent.getBytes());
                    outputStream.close();
                    descriptor.close();
                    writeSuccess = true;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return writeSuccess;
        }
    }
}

Had this exact same issue 6 months ago - drove me absolutely nuts for days. Your code’s fine, it’s just how Google Drive handles file operations through SAF. Here’s what fixed it for me: add descriptor.getFileDescriptor().sync() right after writing but before closing the FileOutputStream. This forces the system to actually commit the data to Google Drive. On Android 7+, Google Drive needs this explicit sync call or it thinks your file’s empty, even though the write worked. Local storage handles this buffering automatically, but Google Drive doesn’t.

This happens because Google Drive changed how it handles file writing in newer Android versions through the Storage Access Framework. The data doesn’t sync properly before the file descriptor closes. I hit this exact issue last year. Here’s what fixed it: wrap your FileOutputStream with BufferedOutputStream and get the flushing sequence right. Use BufferedOutputStream for writing, then flush() it first, flush() the underlying FileOutputStream next, and close everything in reverse order. Google Drive needs this specific flushing pattern to register content properly - local storage doesn’t care as much about incomplete writes.

had same issue, too. using BufferedWriter might help, as google drive can be touchy about data flushing. don’t forget to call flush() before closing the streams. this worked for me on later android versions.