0

読んでくれてありがとう、これを読んでくれる人にたくさん聞いてくれて本当に感謝しています。

アップロードするために、物理ファイルを4096kBのチャンクにカットする必要があります。「もう一方の端」から簡単に拾い上げて作り直すことができます。

この投稿とこの投稿にたくさんの情報があることを感謝しますが、これをすべてエレガントに組み合わせる方法に苦労しています

アイデアは、単に4096kBより大きいファイルを小さな区画にカットすることです。さらに悪いことに、ローカルディスクにファイルを配置せずにファイルの送信を同期的にキューに入れる方法がある場合(つまり、メモリ内でのみ機能する場合)、私は本当にそれを望んでいます。

 //Pseudocode:
 Queue queue = new Queue();
 byte[] currentChunk ;
 int i =0;
 while(currentChunk = openFileinChunks(filename, 4194304)) //4096 kB
 {
      HTTPPoster mypost = new HTTPPoster();
      mypost.add(currentChunk);
      //need comparison here - to know when last loop is happening to use different name :-/ for this next bit
      mypost.uploadedName(filename+"."+ i.ToString().PadLeft(6, '0');
      queue.Enqueue(mypost);
      i++;
 }

 do
 {
    HTTPPoster Post = (HTTPPoster) queue.Dequeue();
    Post.Run();
 } while (queue.Count != 0);

 class HTTPPoster{
     byte[] sendable;
     string tmpname;
     public void add(byte[] toPost)
     {
          sendable = toPost;
     }
     public void uploadedName(string name)
     {
          tmpname = name;
     }
     public void Run()
     {
         //[preferably some condensed reworked code to replace this] **
     }
 }

**:HTTPWebrequest(multipart / form-data)を使用してファイルをアップロードします

4

3 に答える 3

1

この記事http://blogs.msdn.com/b/johan/archive/2009/03/30/1080526.aspxは、似たようなことをしようとするときに非常に便利だと思いました。

この記事のアプローチは比較的簡単です。Webリクエストを設定してから、データのチャンクをストリームに書き込みます。ただし、AllowWriteStreamBufferingfalseに設定すると、リクエストがファイル全体をメモリにバッファリングするのを防ぐことができます。

現在のアプローチの問題は、すべてをメモリに保持しているように見えることです。これにより、大きなファイルで問題が発生する可能性があります。

このサーバーコンポーネントはどのように見えますか?これにより、ファイルの送信に使用する正確な方法が決まる可能性があります。

編集:

これはどうですか?

int bytesRead;
int bufferSize = 4194304;
byte[] buffer = new byte[bufferSize];

using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
    int i = 0;

    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
    {
        string postFileName = Path.GetFileName(filePath) + "." + i++.ToString().PadLeft(10, '0');

        if (bytesRead < bufferSize)
        {
            postFileName = Path.GetFileName(filePath) + ".terminus";
        }

        PostFileChunk(buffer, bytesRead, postFileName);
    }
}

これにより、4 MBのブロックでファイルが読み取られ、PostFileChunkメソッドが呼び出され(HTTPPosterここで再生できます)、サーバーにデータが送信されます。

Runメソッドの投稿にチャンクを書き込むときは、 bytesRead-を使用することに注意してください。バッファーを再利用しているため、最後の読み取りが。未満の場合bufferSizeでも、前回の読み取りのデータの一部が含まれます。bytesReadこれらの文字が書き込まれないようにします。

于 2012-11-19T08:12:19.463 に答える
0

これは機能します。4096B(4096kBではなく)の「チャンク」に減らしましたが、原則は同じです。

注意:私自身のオブジェクト参照が少量あります。これは、jsonFolderおよびjsonDomainと呼ばれるもので、基本的にユーザー名、パスワード、URL、およびファイル情報を保持します。ただし、このロジックに従うことができるはずです。私はこれをチュートリアル(PHPサーバーサイドコードとincron再構築者を含む)に投稿する時間を作るようにします

/******
*   the terminus file format is weird
*   basically it goes like this
*       tmp/myfilename.ext.00000000001  4kB
*       tmp/myfilename.ext.00000000002  4kB
*       tmp/myfilename.ext.00000000003  4kB
*       tmp/myfilename.ext.00000000004  4kB
*       tmp/myfilename.ext.terminus     <=4kB
*   this will re-built here to 
*       dir/myfilename.ext              >16kB <20kB
*/


class classActionType_clientPush : classActionType
{
    string relpath = "";
    jsonFolder myFolder;
    jsonDomain myDomain;
    Queue<HTTPPoster> queue = new Queue<HTTPPoster>();

    /// <param name="relativeLocalFilePath">
    /// this "relativeLocalFilePath" refers to path RE: the ~localFolder~ - this class will cut the file and upload it in 4096kB chunks
    /// </param>
    /// <param name="folder">
    /// use this for the folder pathing
    /// </param>
    /// <param name="domain">
    /// this is for the credentials and the url
    /// </param>
    public void setPath(string relativeLocalFilePath, jsonFolder folder, jsonDomain domain)
    {
        string tmppath = folder.localFolder + relativeLocalFilePath;
        if (File.Exists(tmppath))
        {
            relpath = relativeLocalFilePath;
            myFolder = folder;
            myDomain = domain;
        }
        else
        {
            throw new Exception("classActionType_clientPull.setPath():tmppath \"" + tmppath + "\" does not already exist");
        }
    }

    public override void action()
    {
        if (relpath == "")
        {
            throw new Exception("classActionType_clientPull.action():relpath cannot be \"\"");
        }
        /***
         * split it into chunks and copy file to server
         */
        try
        {

            int bytesRead;
            int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];
            string filePath = myFolder.localFolder + relpath;
            using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                int i = 0;

                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    string postFileName = Path.GetFileName(filePath) + "." + i++.ToString().PadLeft(10, '0');

                    if (bytesRead < bufferSize)
                    {
                        postFileName = Path.GetFileName(filePath) + ".terminus";
                    }

                    HTTPPoster mypost = new HTTPPoster();
                    mypost.add(buffer);
                    mypost.setBytes(bytesRead);
                    mypost.setDomain(this.myDomain);
                    mypost.uploadedName(postFileName);
                    queue.Enqueue(mypost);

                    Debug.WriteLine("   nof: HTTPPoster.action() loop counter " + i + "");
                }
            }

            do
            {
                HTTPPoster Post = (HTTPPoster)queue.Dequeue();
                Post.Run();
            } while (queue.Count != 0);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("   nof: HTTPPoster.action() failed\r\n" + ex.Message + "\r\n" + ex.StackTrace);
        }
    }
}

class HTTPPoster
{
    byte[] sendable;
    string filename;
    int bytes;
    jsonDomain myDomain;

    public void add(byte[] b)
    {
        sendable = b;
    }

    public void uploadedName(string p)
    {
        filename = p;
    }

    public void setDomain(jsonDomain domain)
    {
        myDomain = domain;
    }

    public void setBytes(int bytesRead)
    {
        bytes = bytesRead;
    }

    public void Run()
    {
        try
        {
            /***
             * this does the actual post (!gulp)
             */ 
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(myDomain.url + "/io/clientPush.php");
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            wr.ContentType = "multipart/form-data; boundary=" + boundary;
            wr.Method = "POST";
            wr.KeepAlive = true;
            wr.Credentials = System.Net.CredentialCache.DefaultCredentials;

            Stream rs = wr.GetRequestStream();

            string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";

            string formitem;
            byte[] formitembytes;
            classHasher hash = new classHasher();

            rs.Write(boundarybytes, 0, boundarybytes.Length);
            formitem = string.Format(formdataTemplate, "username", myDomain.user);
            formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
            rs.Write(formitembytes, 0, formitembytes.Length);

            rs.Write(boundarybytes, 0, boundarybytes.Length);
            formitem = string.Format(formdataTemplate, "password", hash.Decrypt(myDomain.password, "saltysaltsalt"));
            formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
            rs.Write(formitembytes, 0, formitembytes.Length);

            rs.Write(boundarybytes, 0, boundarybytes.Length);

            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
            string header = string.Format(headerTemplate, "file", filename, "multipart/mixed");
            byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
            rs.Write(headerbytes, 0, headerbytes.Length);

             rs.Write(sendable, 0, bytes);

            byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
            rs.Write(trailer, 0, trailer.Length);
            rs.Close();

            WebResponse wresp = null;
            try
            {
                wresp = wr.GetResponse();
                Stream myStream = wresp.GetResponseStream();
                StreamReader myReader = new StreamReader(myStream);
                Debug.WriteLine("   nof: HTTPPoster.Run() all ok \r\n" + myReader.ReadToEnd());
            }
            catch (Exception ex)
            {
                Debug.WriteLine("   nof: HTTPPoster.Run() finished\r\n" + ex.Message + "\r\n" + ex.StackTrace);
                if (wresp != null)
                {
                    wresp.Close();
                    wresp = null;
                }
            }
            finally
            {
                wr = null;
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine("   nof: HTTPPoster.Run() !ERROR! \r\n" + ex.Message + "\r\n" + ex.StackTrace);               
        }
    }
}
于 2012-11-19T08:47:46.217 に答える
0

私の解決策:

void LikeThat(byte[] file)
    {

        var ms = new System.IO.MemoryStream(file);
        var b=  new byte[4096];
        while (ms.Length > 0)
        {
            ms.Read(b, 0, 4096);
            //now b contains your chunk, just transmit it!
        }
    }
于 2012-11-18T20:05:45.977 に答える