2012-11-14 42 views
1

我看到ImageIO.read()方法有一個奇怪的行爲。Image IO奇怪的行爲重置輸入流

我將InputStream傳遞給此方法,並且當我第二次嘗試讀取它時,它無法讀取並返回null。

我正嘗試將圖像上傳到Amazon S3,我想創建3個圖像版本。原始和2個縮略圖。我的問題是,當我想創建2個縮略圖時,我需要使用ImageIO.read()讀取InputStream。如果我爲相同的InputStream運行此方法2,則第二次讀取時會得到空值。

我可以通過只讀一個並將相同的BufferedImage傳遞給縮放方法來繞過這個問題。不過,我仍然需要將InputStream傳遞給其他AmazonS3服務以便上傳原始文件。

所以我的問題是沒有人知道ImageIO第一次讀取輸入流後會發生什麼?

下面

public String uploadImage(InputStream stream, String filePath, String fileName, String fileExtension) { 
    try { 

     String originalKey = filePath + fileName + "." + fileExtension; 
     String smallThumbKey = filePath + fileName + ImageConst.Path.SMALL_THUMB + "." + fileExtension; 
     String largetThumbKey = filePath + fileName + ImageConst.Path.LARGE_THUMB + "." + fileExtension; 

     BufferedImage image = ImageIO.read(stream); 
     InputStream smallThumb = createSmallThumb(image, fileExtension); 
     InputStream largeThumb = createLargeThumb(image, fileExtension); 

     uploadFileToS3(originalKey, stream); 
     uploadFileToS3(smallThumbKey, smallThumb); 
     uploadFileToS3(largetThumbKey, largeThumb); 

     return originalKey; 

    } catch (IOException ex) { 
     Logger.getLogger(ManageUser.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    return null; 
} 

回答

1

代碼示例,我想,你可以在一個BufferedInputStream換你原來的輸入流,並使用mark()保存流中的起始位置,並reset()返回到它。

要完全回答你的問題:每個流都被順序讀取(通常有一些內部指針指向當前位置)。在第一個ImageIO.read()之後,流被讀取直到它結束,因此,任何進一步的讀取操作都不會返回任何數據(通常爲-1表示流的結束)。使用mark()可以保存某個位置,之後使用reset()返回。

+1

+1我還建議使用「markSupported()」來檢查原始輸入流是否支持標記,只有當原始輸入流不支持標記時才使用緩衝流。 –

1

ImageIO.read將讀取到輸入流的末尾。這意味着沒有數據需要讀取,這就是爲什麼當您嘗試從中讀取更多數據時您會收到空值。

如果你想重用輸入流,你必須調用它的reset();但只有在底層InputStream實現支持重置時纔有效,請參閱InputStream的markSupported()。

這是簡單的,但天真的修復。

請記住,您已經將圖像讀入內存,因此您並不需要這樣做。這有點笨拙,但可以將它寫出到ByteArrayOutputStream中,然後從中創建一個新的ByteArrayInputStream。

如果我這樣做,我可能會先讀入一個字節數組。查看Commons IOUtils.read()。然後,我會根據需要構建一個新的ByteArrayInputStream和reset(),因爲它肯定支持標記。