2014-03-04 38 views
5

(請參閱編輯對這個問題的底部,如果你不想讀故事的全部。)爲什麼PictureBox.Load鎖定圖像上的一些系統?

嗨,

我是新來的StackOverflow。不要誤解我的意思,我經常使用它。但直到現在,我從未真正發佈過一些東西。這是因爲我沒有什麼新東西可以說,而我的英語不太好。第一件事(可能有)改變了,後者沒有改變。

我碰見了客戶的Windows 7系統問題最近相當。我通過ClickOnce發佈了一個C#.Net 4.0 Windows Forms應用程序。基本上,它是創建位圖文件並將其顯示給用戶的應用程序。如果位圖在創建之前存在,則現有文件首先被刪除。之後,新文件由PictureBox創建並加載。

下面的事情發生在客戶的系統:啓動第一個創建成功申請後 - 第二個及以後的人沒有。該文件不能被刪除,因爲某些進程阻止了它。這個過程就是應用程序本身。

System.IO.IOException:進程無法訪問文件「filename」,因爲它正在被另一個進程使用。

嘛,當然是沒有什麼不尋常。事情是我在幾個系統上測試了這個應用程序。沒有人顯示這個例外。直到現在,我無法看到代碼錯誤。

所以我在客戶的系統上看起來更接近一點:我能找到的唯一區別是,他們更改了users文件夾,以使它們不位於windows分區上,而是位於另一個(C: \ Users - > D:\ Users)。我在網上搜索了一個指令,並在我的一個測試系統上做了同樣的事情。令我驚訝的是,當我運行我的應用程序時,我也遇到了同樣的異常。

有了這使得異常不會再發生我可以改變我的代碼。但我不明白這是爲什麼。所以,也許我的代碼有問題,錯誤只是在特殊情況下顯示出來。或者,也許代碼是好的,原因在於別的地方。我只是希望你能幫助我。

所以這裏是我放在一起的一些代碼,它顯示了相同的行爲。我在窗體上使用了3個按鈕,一個OpenFileDialog和一個PictureBox。首先要做的是選擇一個圖像文件。通過按下其餘兩個按鈕中的一個,它將被複制到應用程序的主文件夾中。複製後,它由PictureBox顯示。順便說一句,這似乎並不重要,如果它是一個ClickOnce應用程序或「正常」的。

String m_FileName; 

private void btnChooseFile_Click(object sender, EventArgs e) { 
    if(openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // If file was chosen, set file name for later use and activate buttons. 
     m_FileName = "Test" + Path.GetExtension(openFileDialog1.FileName); 
    } 
} 

private void button1_Click(object sender, EventArgs e) { 

    // This is not working. 
    if(this.pictureBox1.Image != null) { 
     //Image img = this.pictureBox1.Image; // I was not sure, if maybe the pictureBox somehow prevents the disposing of the image, as long as it's assigned to it. 
     //this.pictureBox1.ImageLocation = null; // So I set them null, both the image and the image location. 
     //this.pictureBox1.Image = null; 
     //img.Dispose(); // Then I disposed the image. 

     this.pictureBox1.Image.Dispose(); // The short version. It is not working either way. 
     this.pictureBox1.Image = null; 
    } 
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); // But still this is where the Exception occurs. 
    this.pictureBox1.Load(m_FileName); 
} 

private void button2_Click(object sender, EventArgs e) { 

    //This is working. 
    if(this.pictureBox1.Image != null) { 
     //Image img = this.pictureBox1.Image; 
     //this.pictureBox1.Image = null; 
     //img.Dispose(); 

     this.pictureBox1.Image.Dispose(); 
     this.pictureBox1.Image = null; 
    } 
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); 
    pictureBox1.Image = Image.FromFile(m_FileName); 
} 

現在發生的情況如下:如果我啓動應用程序並單擊button1兩次,我將得到異常(第二次單擊)。如果我啓動它並點擊按鈕2兩次,我不會。如果我啓動該應用程序並首先單擊按鈕1,然後在該按鈕2之後,我會得到該異常。因此,Picture.Load-Function以某種方式阻止文件,即使我將其丟棄。

當我在網上搜索時,我發現了一篇來自微軟的文章:http://support.microsoft.com/kb/309482/en-us。但它並沒有打到公牛的眼睛。

考慮到這兩個版本都適用於我的所有測試機器。當我將用戶文件夾更改爲非Windows分區時,我只是遇到了異常情況。

這是爲什麼?所提供版本的區別在哪裏?


編輯

好了,因爲迄今爲止第一個也是唯一的反應,在我看來,它仍然是不明確的,到底發生了什麼:如果我把上面的代碼,把它在Windows窗體應用程序中編譯並在不同的計算機上運行(在工作中,在家中,無所謂)它的工作原理 - button1和button2(使用鏈接到它們的Click-函數)可以像我一樣經常使用像 - 沒有例外拋出。如果我在計算機上運行該應用程序,並在其中更改了用戶文件夾,然後第二次單擊button1 - bam - IOException,文件被進程鎖定。只要不按下按鈕1,Button2就會工作。

第一個答案意味着我應該鎖定每個系統。但我不(只要我不更改用戶文件夾)!我在每一臺可以得到我的手的計算機上測試它 - 無IOException。我建立了一個新系統,只是爲了排除我公司系統的一些特殊更改 - buttonx_Click函數都能正常工作 - 也不例外。我甚至在另一臺電腦上編譯了程序 - 同樣的行爲。只有三個引發異常的系統是具有更改的用戶文件夾的系統。

到目前爲止,我還沒有線索,爲什麼會出現這種行爲差異。有人能幫助我嗎?

有人嗎?

回答

6

是的,這是正常的。適用於任何操作系統,與用戶文件夾位置無關。 PictureBox.Load()方法用於從文件系統的位置其他加載圖像。就像一個網站。這是緩慢的,它可以避免在下載過程中凍結用戶界面。

它在內部使用FileStream時,它發現您傳遞的網址實際上是一個文件,而不是一個網站名稱。這個FileStream不會被丟棄,直到PictureBox本身被丟棄,或者你再次調用Load()方法。因爲Image.FromStream()需要流保持可讀性,直到圖像不再使用爲止。正是這個FileStream保持對文件的鎖定。處理PictureBox.Image還不足以配置FileStream,Image對象不知道它正在顯示在一個圖片框中。

有幾種方法來解決這個問題:

  • 使用圖像屬性,而不是裝載的(),從Image.FromFile分配給它()。處置圖像現在還釋放該文件的鎖定。正如你發現的
  • 保持一個虛擬的圖像,可能會顯示一個「Loading ...」位圖。加載()它首先釋放文件上的鎖
  • 配置PictureBox並重新創建它。
+0

雖然我明白了答案,它佔只爲觀察到的行爲的一半。如果事實上它是鎖定圖像的文件流,不應該是所有系統上的行爲都一樣嗎?爲什麼,如果我「癱瘓」系統,我只能得到鎖定行爲? 如果我自己執行FileStream-Version並且不處理FileStream,則會在我所有的測試系統上得到異常(如預期的那樣!)。所以必須有所不同。 – user3379589

+0

我不相信這是特定於某些機器的。您剛收到一位發現該問題的客戶的錯誤報告,並尋找解釋說明爲什麼只有該客戶纔看到它。他們都這樣做,但很容易避免,因爲兩次加載完全相同的圖像並不常見。只需在您自己的機器上重新制作它。 –

+0

上述應用程序(不是上述構造)僅處理單個位圖文件,它創建它自己並向用戶顯示。沒有人能改變它的名字,它是固定的。所以用戶對結果沒有任何影響。 上面的例子是使用較少代碼重現兩種效果的最簡單方法。只要文件格式相同,您可以使用不同的文件名。結果是同名的「Test.fileformat」。但那不是重點。 當我使用上面的示例時,如果您說的話適用,那麼兩個版本都可以在我公司的每個系統上工作,但Version1不應該。 – user3379589