不完整的文件由GridFS返回。

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

Incomplete file returned by GridFS

问题

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

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

  1. ObjectId fileId;
  2. GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
  3. int fileLength = (int) downloadStream.getGridFSFile().getLength();
  4. byte[] bytesToWriteTo = new byte[fileLength];
  5. downloadStream.read(bytesToWriteTo); /*读取文件内容*/
  6. downloadStream.close();
  7. 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.

  1. ObjectId fileId;
  2. GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
  3. int fileLength = (int) downloadStream.getGridFSFile().getLength();
  4. byte[] bytesToWriteTo = new byte[fileLength];
  5. downloadStream.read(bytesToWriteTo); /*read file contents */
  6. downloadStream.close();
  7. System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8));

Any solutions to this?

答案1

得分: 2

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

  1. @Override
  2. public int read(final byte[] b) {
  3. return read(b, 0, b.length);
  4. }
  5. @Override
  6. public int read(final byte[] b, final int off, final int len) {
  7. checkClosed();
  8. if (currentPosition == length) {
  9. return -1;
  10. } else if (buffer == null) {
  11. buffer = getBuffer(chunkIndex);
  12. } else if (bufferOffset == buffer.length) {
  13. chunkIndex += 1;
  14. buffer = getBuffer(chunkIndex);
  15. bufferOffset = 0;
  16. }
  17. int r = Math.min(len, buffer.length - bufferOffset);
  18. System.arraycopy(buffer, bufferOffset, b, off, r);
  19. bufferOffset += r;
  20. currentPosition += r;
  21. return r;
  22. }

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

  1. byte[] bytesToWriteTo = new byte[fileLength];
  2. int bytesRead = 0;
  3. while (bytesRead < fileLength) {
  4. int newBytesRead = downloadStream.read(bytesToWriteTo);
  5. if (newBytesRead == -1) {
  6. throw new Exception();
  7. }
  8. bytesRead += newBytesRead;
  9. }
  10. downloadStream.close();

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

英文:

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

  1. @Override
  2. public int read(final byte[] b) {
  3. return read(b, 0, b.length);
  4. }
  5. @Override
  6. public int read(final byte[] b, final int off, final int len) {
  7. checkClosed();
  8. if (currentPosition == length) {
  9. return -1;
  10. } else if (buffer == null) {
  11. buffer = getBuffer(chunkIndex);
  12. } else if (bufferOffset == buffer.length) {
  13. chunkIndex += 1;
  14. buffer = getBuffer(chunkIndex);
  15. bufferOffset = 0;
  16. }
  17. int r = Math.min(len, buffer.length - bufferOffset);
  18. System.arraycopy(buffer, bufferOffset, b, off, r);
  19. bufferOffset += r;
  20. currentPosition += r;
  21. return r;
  22. }

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

  1. byte[] bytesToWriteTo = new byte[fileLength];
  2. int bytesRead = 0;
  3. while(bytesRead &lt; fileLength) {
  4. int newBytesRead = downloadStream.read(bytesToWriteTo);
  5. if(newBytesRead == -1) {
  6. throw new Exception();
  7. }
  8. bytesRead += newBytesRead;
  9. }
  10. downloadStream.close();

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

答案2

得分: 1

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

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

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

  1. GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId);
  2. int fileLength = (int) downloadStream.getGridFSFile().getLength();
  3. byte[] bytesToWriteTo = new byte[fileLength];
  4. bytesToWriteTo = downloadStream.readAllBytes();
  5. 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:

确定