2015-06-27 53 views
4

This is the image that causes an errorJPEG文件結構無效:兩個SOI標記錯誤?

我有這個問題,我嘗試了我所知道的一切,但沒有任何工作。 我想通過套接字從數據庫發送多個圖像(時間的一個圖像)到客戶端應用程序,有時一切正常,但有時它聲明這個「無效的JPEG文件結構:兩個SOI標記」錯誤?

客戶端:

for(User user : users){ 
    int cmpt=0; 

    byteToread =in.readInt(); 
    bytesOut=new ByteArrayOutputStream(); 
    bos = new BufferedOutputStream(bytesOut);  

    while (byteToread >cmpt) { 
     cmpt = in.read(dataEntre); 
     bos.write(dataEntre, 0, cmpt); 
     bos.flush(); 
     byteToread-=cmpt; 
    } 
    BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytesOut.toByteArray())); 

    user.setPhoto(new ImageIcon(bi)); 
    System.out.println("------------------end"); 
} 
bos.close(); 
bytesOut.close(); 

服務器端:

InputStream input =null; 

Statement myStmt = null; 
ResultSet myRs = null; 
BufferedInputStream bis=null; 
try { 
    myStmt = Conn.createStatement(); 
    myRs = myStmt.executeQuery("select Photo from users order by Name"); 
    byte[] buffer; 

    int k =1; 

    while (myRs.next()) { 
     input=myRs.getBinaryStream("Photo"); 
     bis = new BufferedInputStream(input); 
     buffer = new byte[1024]; 

     try { 
      int byteToread = 0; 
      int cmpt=0; 

      byteToread=input.available(); 
      out.writeInt(byteToread); 
      out.flush(); 

      int i=0; 
      while (byteToread>cmpt) { 
       cmpt = bis.read(buffer); 
       out.write(buffer, 0, cmpt); 
       out.flush(); 
       byteToread -= cmpt; 
      } 
     } catch (IOException ex) { 
      return ; 
     } 
    } 
+0

這個問題剛剛出現最近,我的申請工作了快2個月正常,但現在不知從哪兒 –

+0

這個錯誤這可能是2個月的圖像,你使用沒有觸發這個問題。 這個問題並不完全清楚。另外建議鏈接一個圖像,導致此失敗,以防有人想要自己測試。 (假設圖像沒有版權) – Joeblade

+0

好吧,我會感謝你,那麼我寫的代碼怎麼樣,特別是客戶端 –

回答

2

首先第一件事情: 錯誤遇到:

每個JPEG圖像總是開始於StartOfImage標誌物以十六進制表示:FFD8 您正在創建的緩衝區中的字節包含這個SOI標記兩次。 這很可能是您獲取圖像1的字節+ image2的某些字節,特別是包含第二個圖像標記的起始字節。

我覺得你在這裏犯了一個錯誤:

​​

就拿,你一共有100個字節的情況。 由於某些原因,您將以50,30,20字節爲單位讀取這100個字節。

這將給以下內容:

iteration 1: 
during while: 
    bytesToRead: 100 
    cmpt: 0 
at the end of the loop: 
    bytesToRead: 50 
    cmpt: 50 
iteration 2: 
during while: 
    bytesToRead: 50 
    cmpt: 50 

在這一點上,byteToRead(50)不是>,而你不寫過去的50個字節比CMPT(50),因此循環結束。

你可能需要類似:

bytesToread = in.readInt(); 
bytesOut=new ByteArrayOutputStream(); 
bos = new BufferedOutputStream(bytesOut);  
while (byteToread > 0) { 
    cmpt = in.read(dataEntre); 
    bos.write(dataEntre, 0, cmpt); 
    bos.flush(); 
    byteToread-=cmpt; 
} 

可能與小圖片,你會讀出字節的全部金額一氣呵成(雖然這並不能完全保證,但只是可能)。如果發生這種情況,那麼您將在一次迭代中完成並且永遠不會遇到問題。但是對於較大的圖像,您可能會冒着讀取的最後一個塊導致圖像末尾丟失一些字節的風險。這可能會導致麻煩(我認爲)

的第二個問題可能是(在服務器端)

byteToread=input.available(); 

你從數據庫獲取的結果集可能不具有所有可用的字節,你還沒有使用。

從可用的()

注意的文件,儘管InputStream的一些實現將流中返回的字節總數,許多人不會。使用此方法的返回值分配旨在保存此流中所有數據的緩衝區永遠是不正確的。

從我可以看到,地方出了錯(基於我的測試程序)會發生以下情況:

1:你得到此搜索(比如200個字節)。 2:將長度(200)寫入您的輸出流 3:您向輸出流寫入少於200字節(比如150)。 (因爲錯誤的邏輯) 4:你得到image2(比如300字節) 5:你寫長度(300)到你的輸出流 6:你寫N個字節到輸出流。

當您閱讀

1:you read image1.length。這將返回200. 2:您讀取200個字節。因爲你只從圖像1寫入了150個字節,這意味着你從image1獲得了150個字節,image2的長度,然後是來自image2的46個字節。

這會導致您認爲圖像1中包含2個JPG標頭的字節。 (image2的前46個字節將包含image2的頭文件)

我認爲你需要附加你的調試器,並逐步瞭解這一點,並找出其他問題。給出的另一個答案顯示瞭如何循環並正確計數您的讀取字節。可能會有更多的問題。

+0

是啊這樣做,但也像你說的它會導致錯過一些字節,代碼我寫我大多數時間工作,但有時它不, –

+0

在我的回答中,我解釋了爲什麼(我認爲)它有時有效,其他時間沒有。您無法控制應用程序隨時讀取的字節數。嘗試使用while(byteToRead> 0)並查看它是否更好。 – Joeblade

+0

我做了,服務器確實發送了每個圖像和每個字節,客戶端應用程序沒有聲明任何錯誤,但執行不會繼續執行下一步或下一條指令,它就像輸入套接字仍在等待更多數據,但服務器已經發送每一個並且向前移動 –

4

請勿使用available()作爲輸入長度的度量。 Javadoc對此有一個特別的警告。這不是它的目的。

你的副本循環應該是這樣的:

while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
}