Google 驱动器 & Android - 读取失败:EBADF(错误文件编号)

Google Drive & Android - read failed: EBADF (Bad file number)

所以我有一段代码可以在我可以访问的所有设备和模拟器上正常工作,除了一个。这是一台便宜的旧 Android 设备,华为 Y330-U01,运行 4.2.2。我正在使用 com.google.android.gms:play-services-drive:9.8.0 进行编译。据我所知,这绝对是标准的。

我得到了超过 1 兆字节的纯文本文件,我可以一个字符一个字符地读取它,有几千个字符(数量各不相同,而不是介于 2 的幂或任何数字之间) , 在得到错误之前

IOException while testing the stream's first character
java.io.IOException: read failed: EBADF (Bad file number)
    at libcore.io.IoBridge.read(IoBridge.java:486)
    at java.io.FileInputStream.read(FileInputStream.java:179)
    at libcore.io.Streams.readSingleByte(Streams.java:41)
    at java.io.FileInputStream.read(FileInputStream.java:175)
    at com.suchideas.android.alamode.sync.SyncActivity$b.run(Unknown Source)
 Caused by: libcore.io.ErrnoException: read failed: EBADF (Bad file number)
    at libcore.io.Posix.readBytes(Native Method)
    at libcore.io.Posix.read(Posix.java:123)
    at libcore.io.BlockGuardOs.read(BlockGuardOs.java:149)
    at libcore.io.IoBridge.read(IoBridge.java:476)
    at java.io.FileInputStream.read(FileInputStream.java:179) 
    at libcore.io.Streams.readSingleByte(Streams.java:41) 
    at java.io.FileInputStream.read(FileInputStream.java:175) 
    at com.suchideas.android.alamode.sync.SyncActivity$b.run(Unknown Source) 

我非常有信心这是 运行 RAM 或磁盘 space(当然 足够了 space 对于这个文件,数百兆字节,但设备确实喜欢抱怨存储)并清除实际使用的东西。再次重申,此代码在相同 Android 版本的模拟器和所有其他测试设备上完美运行

所以。您觉得有解决办法吗?

这是代码,您应该可以填补空白...

if (!mGoogleApiClient.isConnected()) {
    mGoogleApiClient.connect();
    while (mGoogleApiClient.isConnecting()) {
        try {
            sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    if (!mGoogleApiClient.isConnected())
        return;
}

appFolder = Drive.DriveApi.getAppFolder(mGoogleApiClient);
Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, UPLOADED_DATABASE_NAME))
        .build();
DriveApi.MetadataBufferResult metadataBufferResult = appFolder.queryChildren(mGoogleApiClient, query).await();
if (!metadataBufferResult.getStatus().isSuccess()) {
    metadataBufferResult.release();
    return;
}

MetadataBuffer databaseFileResults = metadataBufferResult.getMetadataBuffer();
if (databaseFileResults.getCount() == 0) {
    return;
}
Metadata md = databaseFileResults.get(0);
Log.d(TAG, "Database file retrieved [" + md.getFileSize() + "B]. Created " + md.getCreatedDate() + ", modified " + md.getModifiedDate() + ".");
DriveId databaseFileID = md.getDriveId();
databaseFileResults.release();
metadataBufferResult.release();

DriveFile databaseFile = databaseFileID.asDriveFile();
DriveApi.DriveContentsResult driveContentsResult = databaseFile.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, new DriveFile.DownloadProgressListener() {
    @Override
    public void onProgress(long downloaded, long expected) {

    }
}).await();
if (!driveContentsResult.getStatus().isSuccess()) {
    return;
}
DriveContents driveContents = driveContentsResult.getDriveContents();

InputStream in = driveContents.getInputStream();

try {
    int c = 0;
    for(int i = 0; true; i++) {
        c = in.read();
        if(c == -1) break;
        Log.d(TAG, "Character "+i+": "+(char)c);
    }
} catch (IOException e) {
    Log.e(TAG, "IOException while testing the stream character", e);
    return;
}

好的,所以几乎肯定可以做得比这更好(我不认为你需要逐个字符地阅读,一些缓冲可能没问题),但经过几个小时的战斗,我找到了一种方法避免在此设备上触发问题。

在实践中,我建议先尝试正常 driveContents.getInputStream()。这样就可以捕捉到上面讨论的那种错误,只有在必要时才转向这种方法。

但它有效。

方法:直接从 FileDescriptor 打开 DriveContents,而不是通过 InputStream。逐渐在缓冲区中构建它(我在这里只使用 StringBuilder,因为这是概念验证)。捕获 IOExceptions,如果您至少已成功读取 一些 数据,请重新开始,继续前进,直到到达字符串的末尾。

private static String safeDriveFileToString(DriveContents driveContents) throws IOException {
    StringBuilder sb = new StringBuilder();

    InputStream in;

    int n = 0, nPrevious = 0;
    while(true) {
        in = new FileInputStream(driveContents.getParcelFileDescriptor().getFileDescriptor());
        try {
            int toSkip = n;
            while(toSkip > 0) {
                toSkip -= in.skip(toSkip);
            }

            int c;
            while ((c = in.read()) != -1) {
                sb.append((char) c);
                n++;
            }

            if(c == -1) break;
        } catch (IOException e) {
            if(nPrevious == n) {
                throw e;
            } else {
                Log.e(TAG, "Ignoring error part-way through a file:", e);
            }
            nPrevious = n;
        }
    }

    return sb.toString();
}

想知道最奇怪的事情吗?在用这种方法读过一次这个文件后,它现在总是可以工作而不需要求助于这个。 绝对奇怪。