不完整的文件由GridFS返回。

huangapple go评论68阅读模式
英文:

Incomplete file returned by GridFS

问题

我正在进行一个Java项目,使用GridFS规范将文件存储到MongoDB并从中检索文件。我正在使用MongoDB Java驱动文档中在<https://mongodb.github.io/mongo-java-driver/4.1/driver/tutorials/gridfs/>提供的代码片段。

在使用OpenDownloadStream检索文件时,我注意到,如果文件被分成多个块,它只返回第一个块,而不是完整的文件。

ObjectId fileId;

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
int fileLength = (int) downloadStream.getGridFSFile().getLength();
byte[] bytesToWriteTo = new byte[fileLength];
downloadStream.read(bytesToWriteTo);    /*读取文件内容*/
downloadStream.close();

System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8));

有解决这个问题的方法吗?

英文:

I'm working on a Java project to store and retrieve files from MongoDB using GridFS specification. I'm using the code snippets provided in MongoDB Java driver documentation from <https://mongodb.github.io/mongo-java-driver/4.1/driver/tutorials/gridfs/>.

While using OpenDownloadStream to retrieve the file, I noticed that if the file is divided into more than one chunks, it returns only the first chunk, and not the full file.

ObjectId fileId;

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
int fileLength = (int) downloadStream.getGridFSFile().getLength();
byte[] bytesToWriteTo = new byte[fileLength];
downloadStream.read(bytesToWriteTo);    /*read file contents */
downloadStream.close();

System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8));

Any solutions to this?

答案1

得分: 2

看一下实现了GridFSDownloadStream接口的GridFSDownloadStreamImpl类,它似乎是通过分块来实现read(byte[])方法:

@Override
public int read(final byte[] b) {
    return read(b, 0, b.length);
}

@Override
public int read(final byte[] b, final int off, final int len) {
    checkClosed();

    if (currentPosition == length) {
        return -1;
    } else if (buffer == null) {
        buffer = getBuffer(chunkIndex);
    } else if (bufferOffset == buffer.length) {
        chunkIndex += 1;
        buffer = getBuffer(chunkIndex);
        bufferOffset = 0;
    }

    int r = Math.min(len, buffer.length - bufferOffset);
    System.arraycopy(buffer, bufferOffset, b, off, r);
    bufferOffset += r;
    currentPosition += r;
    return r;
}

因此,你必须循环直到实际读取了所有预期的字节:

byte[] bytesToWriteTo = new byte[fileLength];
int bytesRead = 0;
while (bytesRead < fileLength) {
    int newBytesRead = downloadStream.read(bytesToWriteTo);
    if (newBytesRead == -1) {
        throw new Exception();
    }
    bytesRead += newBytesRead;
}
downloadStream.close();

请注意,我无法对上述代码进行测试,请谨慎使用。

英文:

Looking at the class GridFSDownloadStreamImpl which implements GridFSDownloadStream, it looks like the method read(byte[]) reads chunk by chunk:

@Override
public int read(final byte[] b) {
    return read(b, 0, b.length);
}

@Override
public int read(final byte[] b, final int off, final int len) {
    checkClosed();

    if (currentPosition == length) {
        return -1;
    } else if (buffer == null) {
        buffer = getBuffer(chunkIndex);
    } else if (bufferOffset == buffer.length) {
        chunkIndex += 1;
        buffer = getBuffer(chunkIndex);
        bufferOffset = 0;
    }

    int r = Math.min(len, buffer.length - bufferOffset);
    System.arraycopy(buffer, bufferOffset, b, off, r);
    bufferOffset += r;
    currentPosition += r;
    return r;
}

Therefore, you have to loop until all expected bytes are actually read:

byte[] bytesToWriteTo = new byte[fileLength];
int bytesRead = 0;
while(bytesRead &lt; fileLength) {
    int newBytesRead = downloadStream.read(bytesToWriteTo);
    if(newBytesRead == -1) {
        throw new Exception();
    }
    bytesRead += newBytesRead;
}
downloadStream.close();

Note that I was not able to test above code so please use with caution.

答案2

得分: 1

我最终使用了 readAllBytes() 方法,它会返回整个文件。

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
int fileLength = (int) downloadStream.getGridFSFile().getLength();
byte[] bytesToWriteTo = new byte[fileLength];
bytesToWriteTo = downloadStream.readAllBytes();
downloadStream.close();
英文:

I ended up using readAllBytes() method and it returns the whole file.

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
int fileLength = (int) downloadStream.getGridFSFile().getLength();
byte[] bytesToWriteTo = new byte[fileLength];
bytesToWriteTo = downloadStream.readAllBytes();
downloadStream.close();

huangapple
  • 本文由 发表于 2020年9月10日 19:26:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/63828715.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定