0

HTML5 キャンバス要素と新しい HTML5 ファイル i\o 関数を使用して、複数のファイルをドロップしてアップロードします。正常に動作しますが、宛先ディレクトリにファイルがない場合 (7 桁の整数)、新しいファイル名を生成するか、最後にアップロードされたファイルの名前を取得して int32 に変換し、新しいファイルごとに 1 ずつ増やす必要があります。ファイルが同じディレクトリにアップロードされます。これは、GetFileName(dir);最初の画像は常に正常にアップロードされますが、2 番目のファイルが保存され、プロセスが ImageJob.Build() に到達すると問題が発生します。これは、新しいファイルの書き込みが開始されると、GetFile() メソッドが実行されるためだと思います。 2 番目のファイルが同時に行にあり、最後に書き込まれたファイルをチェックしています。このファイルはまだ書き込まれているため、競合が発生します。どうすればこれを修正できますか?おそらく、Request.InputStream データに対して foreach を反復処理したり、プロセスが終了するのを待機する何らかのプロセス ウォッチを実装したりできますか?

Update:TempData を使用して生成されたファイル名を保存しようとしましたが、次のすべてのファイル名に対して TempData の int 値をインクリメントするだけで、うまくいくように見え、より多くの画像を取得できますが、ある時点でまだエラーが発生します。ただし、TempData は読み取りのたびに消去されるため、そのためではありません。もう一度割り当て直しても役に立ちません。多分私はそれをセッションに保存しようとします。

別のプロセスで使用されているため、プロセスはファイル 'C:\Users\Admin\Documents\Visual Studio 2010\Projects\myproj\myproj\Content\photoAlbums\59\31\9337822.jpg' にアクセスできません。

public PartialViewResult Upload()
{          
    string fileName = Request.Headers["filename"];
    string catid = Request.Headers["catid"];
    string pageid = Request.Headers["pageid"];
    string albumname = Request.Headers["albumname"];


    var dir = "~/Content/photoAlbums/" + catid + "/" + pageid + "/" + (albumname ?? null);

    var noex = GetFileName(dir);

    var extension = ".jpg";

    string thumbFile = noex + "_t" + extension;
    fileName = noex + extension;

    byte[] file = new byte[Request.ContentLength];
    Request.InputStream.Read(file, 0, Request.ContentLength);

    string imgdir;
    string thumbimgdir;
    string imageurl;

    if (albumname != null) 
    { 
        imgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + fileName);
        thumbimgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + thumbFile);
        imageurl = "/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + thumbFile;
    }
    else 
    { 
        imgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + fileName);
        thumbimgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + thumbFile);
        imageurl = "/Content/photoAlbums/" + catid + "/" + pageid + "/" + thumbFile;
    }

    ImageJob b = new ImageJob(file, imgdir, new ResizeSettings("maxwidth=1024&maxheight=768&format=jpg")); b.CreateParentDirectory = true; b.Build();
    ImageJob a = new ImageJob(file, thumbimgdir, new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();

    ViewBag.CatID = catid;
    ViewBag.PageID = pageid;
    ViewBag.FileName = fileName;

    return PartialView("AlbumImage", imageurl);
}

public string GetFileName(string dir)
{
    var FullPath = Server.MapPath(dir);
    var dinfo = new DirectoryInfo(FullPath);

    string FileName;
    if (dinfo.Exists)
    {           
       var Filex = dinfo.EnumerateFiles().OrderBy(x => x.Name).LastOrDefault();
       FileName = Filex != null ? Path.GetFileNameWithoutExtension(Filex.Name) : null;

       if (FileName != null)
       {
           FileName = FileName.Contains("_t") ? FileName.Substring(0, FileName.Length - 2) : FileName;
           int fnum;
           Int32.TryParse(FileName, out fnum);
           FileName = (fnum + 1).ToString();

           if (fnum > 999999) { return FileName; } //Check that TryParse produced valid int
           else 
           {
              var random = new Random();
              FileName = random.Next(1000000, 9999000).ToString();
           }
       }
       else
       {
           var random = new Random();
           FileName = random.Next(1000000, 9999000).ToString();
       }
    }
    else
    {        
           var random = new Random();
           FileName = random.Next(1000000, 9999000).ToString();
    }
    return FileName;
}
4

2 に答える 2

2

一意のファイル名を生成したい場合は、Random クラスを使用することはできません。現在の時刻をシードとして使用するため、2 つの正確な同時要求は常に同じ「乱数」を生成します。

暗号乱数ジェネレーターを使用することもできますが、(a) 一度に 1 つのスレッドのみが乱数を生成すること、および (b)誕生日のパラドックスを防ぐために十分に長い ID を使用することを保証する必要があります。

したがって、上記の問題はすべて本質的に解決されるため、すべての人がアップロードに GUID 識別子を使用することをお勧めします(重複を防ぐために OS レベルのロックが使用されていると思います)。

あなたのメソッドは、意図的なものかもしれませんが、リクエストごとに複数のファイルのアップロードも処理しません。Request.FilesHttpPostedFileインスタンスをループして ImageJob に直接渡すことで、これらをサポートできます。

これは、GUID を使用し、同時実行の問題が発生しないコードの簡略化されたバージョンです。

public PartialViewResult Upload()
{          

    string albumname = Request.Headers["albumname"];
    string baseDir = "~/Content/photoAlbums/" + Request.Headers["catid"] + "/" + Request.Headers["pageid"] + "/" (albumname != null ?  albumname + "/" : "");

    byte[] file = new byte[Request.ContentLength];
    Request.InputStream.Read(file, 0, Request.ContentLength);

    ImageJob b = new ImageJob(file, baseDir + "<guid>.<ext>", new ResizeSettings("maxwidth=1024&maxheight=768&format=jpg")); b.CreateParentDirectory = true; b.Build();
    ImageJob a = new ImageJob(file, baseDir + "<guid>_t.<ext>", new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();

    //Want both the have the same GUID? Pull it from the previous job.
    //string ext = PathUtils.GetExtension(b.FinalPath);
    //ImageJob a = new ImageJob(file, PathUtils.RemoveExtension(a.FinalPath) + "_t." + ext, new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();


    ViewBag.CatID = Request.Headers["catid"];
    ViewBag.PageID = Request.Headers["pageid"];
    ViewBag.FileName = Request.Headers["filename"];

    return PartialView("AlbumImage", PathUtils.GuessVirtualPath(a.FinalPath));
}
于 2012-06-07T14:30:04.333 に答える
1

プロセスが比較的高速 (小さなファイル) の場合は、ループに入ってその例外をチェックし、スレッドを数秒間スリープさせてから、再試行できます (反復の最大数まで)。1 つの注意点は、アップロードが非同期の場合、ファイルを見逃す可能性があることです。

他のいくつかの提案:

  • Web からトリガーされないように、GetFileName をプライベート メソッドにします。
  • Filex クエリの OrderBy は、8 桁になると期待どおりに動作しない可能性があります (最初の Random() が非常に大きな数値である場合に発生する可能性があります)。
  • Random() は、より良いランダム性を生成するためにおそらくシードする必要があります。
于 2012-06-07T13:20:20.213 に答える