6

なのでC#を使って登録システムを作っています。写真を追加するオプションがあり、私が行うことは、ユーザーにファイルを選択するように求めると、そのファイルがディレクトリ フォルダーにコピーされ、学生の入学番号に名前が変更されます。その参照ボタンのコードは次のとおりです。

OpenFileDialog openDlg = new OpenFileDialog();
            openDlg.Filter = "All JPEG files (*.jpg; *.jpeg)| *.jpg; *.jpeg";
            string filter = openDlg.Filter;
            openDlg.Multiselect = false;
            openDlg.Title = "Open a JPG File";
            if (openDlg.ShowDialog() == DialogResult.OK)
            {                
                curFileName = openDlg.SafeFileName;
                string curFilePath = openDlg.FileName;

                openDlg.Dispose();

                string sourcePath = @curFilePath.Remove((curFilePath.Length - curFileName.Length));
                string targetPath = "@";

                mycon.Open();
                string cmdstr = "SELECT imageDirectory from userSettings WHERE ID = 1";
                cmd = new OleDbCommand(cmdstr, mycon);
                dr = cmd.ExecuteReader();
                while (dr.Read())
                {
                    targetPath = (@dr["imageDirectory"].ToString());
                }
                dr.Close();
                mycon.Close();

                string sourceFile = Path.Combine(sourcePath, curFileName);
                string destFile = Path.Combine(targetPath, curFileName);

                File.Copy(sourceFile, destFile, true);

                newname = @destFile.Remove((destFile.Length - curFileName.Length)).ToString() + "\\" + (DateTime.Now.Year + "-" + textBox1.Text+".jpeg");

                if (File.Exists(newname) == true)
                {
                    pictureBox1.Image.Dispose();
                    try
                    {
                        File.Delete(newname);
                    }

                    catch (IOException ex)
                    {
                        MessageBox.Show(ex.ToString());
                        return;
                    }
                }

                File.Move(destFile, newname);

                photoPath = newname;
                pictureBox1.Image = Image.FromFile(photoPath);

問題は次のとおりです。

a.) ユーザーが次のステップに進むことができるようにする機能があり、最後のステップで変更を加えたい場合は、戻って更新することができます。ここでの問題は、彼が画像を変更したときに、「別のプロセスで使用されているため、ファイルにアクセスできません」というエラーが表示されることです。

b.) ユーザーがすでに写真をアップロードしてからホームページに戻った場合、再度登録することを決定したときに新しい写真をアップロードすることはできず、次のエラーが表示されます。別のプロセスで使用されています。」

2つのエラーは両方ともここを指しています:

`File.Delete(newname);`

昨夜からこれに対する解決策を探していましたが、コード全体を完全に変更しないような解決策が見つかりません。助けてください :(

4

2 に答える 2

8

あなたのコードは正しいです。コードの匂いについての意見は無視してください。PictureBox.Image を破棄することは、メモリ不足の例外を回避するために重要です。

この問題は、Bitmap クラスの実装の詳細が原因で発生します。画像ファイルを開くと、クラスはメモリ マップト ファイルを作成して、画像のピクセル データをメモリにマップします。これは大きな画像の重要な最適化であり、ページング ファイルからピクセル データを除外します。GDI+ が設計されてから 15 年が経過した今日では、それほど重要ではありませんが、最新のマシンには大量の RAM とディスク容量があります。

ただし、そのメモリ マップト ファイルは、ファイルにロックを作成します。ファイルデータをいじったり、ファイルのマップされたビューを無効にしたりする他のプロセスを防ぐことが重要です。これは、ファイルを置き換えたり削除しようとしても機能しなくなったということです。これを回避するには、ビットマップのディープ コピー (すべてのピクセル データがメモリ内にあり、ファイルを使用しないコピー) を作成します。このような:

public static Bitmap LoadBitmapNolock(string path) {
    using (var img = Image.FromFile(path)) {
        return new Bitmap(img);
    }
}

このコードを使用すると、32 ビット バージョンの Windows で大きな画像を使用するとメモリ不足になる可能性が大幅に高まることに注意してください。

于 2012-10-14T10:21:46.083 に答える
1

.Dispose()マネージ言語 (C# など) での の手動使用はCode Smellです。リソースを手動で管理しようとしているため、無効な状態になる可能性があります。これを回避できる可能性のある 2 つの方法は次のとおりです。

  1. .Dispose()不要な要素 ( など)を取り除くopnDlg.Dispose()、および/または
  2. 破棄が必要なオブジェクトをusing(...){...}ステートメントでラップしてみてください

.Dispose()いずれにせよ、コードをリファクタリングした後は、その中にメソッド呼び出しが含まれていてはなりません。使用しているオブジェクトは、手動で管理する必要がなく、そうしようとしても問題が発生するだけであるか、または絶対に管理する必要があるため、using(...)ステートメントはリソースの解放を保証するため、はるかに優れています。コードブロックを終了します。

于 2012-10-14T06:17:07.600 に答える