1

Here is my code flow for which file content is getting lost and I think may be IOUtils.toByteArray() line is problem, please guide what is actually going wrong here.

File content getting lost :

InputStream stream = someClient.downloadApi(fileId);
byte[] bytes = IOUtils.toByteArray(stream); 
String mimeType = CommonUtils.fileTypeFromByteArray(bytes);
String fileExtension=FormatToExtensionMapping.getByFormat(mimeType).getExtension();
String filePath = configuration.getDownloadFolder() + "/" ;
String fileName = UUID.randomUUID() + fileExtension;    
File file = new File(filePath+fileName);    
file.createNewFile();    
FileUtils.copyInputStreamToFile(stream,file);    
int length = (int)file.length();

Now length value here is 0 basically no content. Let me tell you that inputStream received from downloadApi() has content for sure thats given. But if I try below modification in code then I'm getting length of file.

File content NOT getting lost:

InputStream stream = someClient.downloadApi(fileId);
byte[] bytes = IOUtils.toByteArray(stream);
String mimeType = CommonUtils.fileTypeFromByteArray(bytes);
String fileExtension=FormatToExtensionMapping.getByFormat(mimeType).getExtension();
String filePath = configuration.getDownloadFolder() + "/" ;
String fileName = UUID.randomUUID() + fileExtension;
stream = new ByteArrayInputStream(bytes); //Again converted bytes to stream    
File file = new File(filePath+fileName);    
file.createNewFile();    
FileUtils.copyInputStreamToFile(stream,file);    
int length = (int)file.length();

Now here I'm getting file content. Can some body tell what is technically wrong here in first code snippet ?

TIA

Abhishek
  • 1,558
  • 16
  • 28
  • 1
    I would start by: dumping the result of `toByteArray()`. Your second example looks weird, it should actually not do anything. You can't "reset" a stream ... Dont go for "file length", check the **content** that gets written to disk. – GhostCat Nov 13 '18 at 13:08
  • 1
    Also, does `ByteArrayInputStream` really take `InputStream` as input? – CS_noob Nov 13 '18 at 13:09
  • @GhostCat yes I've checked the downloaded file and it has `no content` for first snippet but has content for second snippet. Length is just example to tell it has no content. – Abhishek Nov 13 '18 at 13:15
  • @CS_noob thanks! updated the code accordingly. – Abhishek Nov 13 '18 at 13:24

2 Answers2

5

No it doesn't.

The first version of your code (reproduced below with some added commentary) fails because you are reading from a stream that is already at the end of stream position.

InputStream stream = someClient.downloadApi(fileId);

// This reads the entire stream to the end of stream.
byte[] bytes = IOUtils.toByteArray(stream);

String mimeType = CommonUtils.fileTypeFromByteArray(bytes);
String fileExtension = 
        FormatToExtensionMapping.getByFormat(mimeType).getExtension();
String filePath = configuration.getDownloadFolder() + "/" ;
String fileName = UUID.randomUUID() + fileExtension;    
File file = new File(filePath+fileName);    
file.createNewFile();    

// Now you attempt to read more data from the stream.
FileUtils.copyInputStreamToFile(stream,file);    

int length = (int)file.length();

When you try to copy from a stream that is at the end of stream, you get ... zero bytes. And that means you get an empty output file.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Awesome! Thanks this really explains why I was getting zero bytes in first place. Also, it tells that if we are using `IOUtils.toByteArray(stream);` then after that stream object should not be used for any kind of modification on stream object as it has moved to EOF except `stream.close()`. – Abhishek Nov 13 '18 at 14:58
1

No, this stream should be closed.

This is target method of IOUtils:

public static long copyLarge(final InputStream input, final OutputStream output, final byte[] buffer)
        throws IOException {
    long count = 0;
    int n;
    while (EOF != (n = input.read(buffer))) {
        output.write(buffer, 0, n);
        count += n;
    }
    return count;
}

// create stream and use it
InputStream stream = someClient.downloadApi(fileId);
byte[] bytes = IOUtils.toByteArray(stream); 

// then us it again
FileUtils.copyInputStreamToFile(stream,file);

// FIXED VERSION
FileUtils.copyInputStreamToFile(new ByteArrayInputStream(bytes),file);
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • Thanks for quick response! And I totally understand that stream should be closed here but above two codes behaving weird please review once and can explain whats going wrong there why content getting lost would be great. – Abhishek Nov 13 '18 at 13:19
  • Yes your // FIXED VERSION code what I was doing in my second snippet. Thanks! – Abhishek Nov 13 '18 at 15:01