Google Drive 和 Android - 读取失败:EBADF(错误文件编号)



所以我有一段代码可以在我可以访问的所有设备和模拟器上正确工作,除了一个。这是一款廉价的老式安卓设备,名为华为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或磁盘空间耗尽的情况(当然有足够的空间来存储这个文件,有数百兆字节,但设备确实喜欢抱怨存储),并清除实际正在使用的东西。再次重申,这段代码在相同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();
}

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

最新更新