android - Google 云端硬盘和 Android - 读取失败 : EBADF (Bad file number)

标签 android google-drive-android-api

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

我得到了这个文件,它是超过一兆字节的纯文本,我可以逐个字符地读取它,读取几千个字符(数量各不相同,而不是在二的幂或其他数字之间)得到错误

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();
}

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

关于android - Google 云端硬盘和 Android - 读取失败 : EBADF (Bad file number),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40368113/

相关文章:

android - 无法使用 Espresso 启动应用程序

java - 基于编辑文本输入的微调器值

google-drive-api - 新的 Google Drive Android API (GDAA) 中报告的已删除文件状态不可靠

google-drive-api - 垃圾桶,要在新的Google Drive Android API中删除吗?

android - 使用 Android 打开 Google 云端硬盘中的特定文件夹

android - Google Maps Android API v2 : Failed to Load Map. 无法联系 Google 服务器

java - Android AES解密返回稀有字符

Android:如何防止软键盘将我的 View 向上推?

java - 使用哪一个进行 Google Drive 集成

google-drive-api - Google Drive 的 FileID 格式是什么?我需要使用 API 查明新文件是否已上传到我的驱动器