c#文件上传下载之基本流程

      前几天做了个文件上传下载的例子,就是对Blob对象的上传下载,现把其中遇到的问题以及解决方法在这里再顺一遍。

      大家都知道我们的文件是保存在硬盘,也就是外存中的,那我们在上传的时候就要先把文件调入到内存。而内存的容量是有限的,如果我们的文件过于庞大,就会占用太多的内存,所以我们就要把文件分块,然后再把文件一块一块的读入到内存缓冲区中,然后再把缓冲区中的数据读到数据库Blob对象里。那这个Blob对象又是哪来的呢,这就要求我们先向数据库中注册文件的其它信息,包括文件名,文件类型,上传时间等信息,然后同时返回Blob对象名。所以我们需要建一个类来保存文件的信息,以及控制对文件的读写。好,上传大概就是这么一个过程,那下面我们来结合代码再顺一遍。

  • 先对一些变量进行初始化 ,这些变量都是文件类fileInfo里的。
buffer = new byte[blockSize];//建立缓冲区数组
inputStream = new FileStream(path , FileMode.Open, FileAccess.Read, FileShare.Read,4* 1024*1024, true);//建立读文件的数据流 fileSize = inputStream.Length;//获取文件大小 blockCount = (int)(fileSize / blockSize)+1;//对文件进行分块
  • 对文件其它信息进行注册,并返回Blob对象
private OracleTransaction insert()//注册文件信息
{
                OracleConnection conn = new OracleConnection(connString);
           
                OracleCommand cmd = new OracleCommand("system.form_zhu.file_insert", conn);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.BindByName = true;


                OracleParameter para_fileName = new OracleParameter("paraName", fileInfo.fileName);//文件名
                para_fileName.Direction = ParameterDirection.Input;
                cmd.Parameters.Add(para_fileName);

                OracleParameter para_fileType = new OracleParameter("paraType", fileInfo.fileType);//类型
                para_fileType.Direction = ParameterDirection.Input;
                cmd.Parameters.Add(para_fileType);

                OracleParameter where_string = new OracleParameter("paraString", OracleDbType.Varchar2);//返回where_string
                where_string.Direction = ParameterDirection.Output;
                where_string.Size = 200;
                cmd.Parameters.Add(where_string);

                conn.Open();
                OracleTransaction txn = conn.BeginTransaction();//开启事务
cmd.ExecuteNonQuery();


此处用了事务处理,注册的时候开启事务,直到写完成的的时候结束事务,以遍读写中断的时候可以回滚重新进行读写。

 private void blob(OracleTransaction txn)//获取Blob对象
       {
           

                OracleCommand cmd = new OracleCommand("system.FORM_ZHU.getBlob", txn.Connection);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.BindByName = true;

                OracleParameter para_tableName = new OracleParameter("tableName", this .tableName );//表名
                para_tableName.Direction = ParameterDirection.Input;
                cmd.Parameters.Add(para_tableName);

                OracleParameter para_blobName = new OracleParameter("blobName", this.blobName );//Blob对象列名
                para_blobName.Direction = ParameterDirection.Input;
                cmd.Parameters.Add(para_blobName);

                OracleParameter para_Wblob = new OracleParameter("whereString",whereString );//Blob对象地址
                para_Wblob.Direction = ParameterDirection.Input;
                cmd.Parameters.Add(para_Wblob);


                OracleParameter blob = new OracleParameter("temp_blob", OracleDbType.Blob);//返回Blob对象
                blob.Direction = ParameterDirection.ReturnValue ;
                blob.Size = 200000;
                cmd.Parameters.Add(blob);

                cmd.ExecuteNonQuery();
                fileContent =(OracleBlob ) blob.Value;

此处用的连接还是上面事务的连接,用来获取OracleBlob对象,赋值给FileInfo类的FileContent变量。

  • 然后主窗体调用FileInfo里的Read方法,此处的读写为异步读写。何为异步读写,就是开辟另一个线程,和主线程同时在运行,互不干扰。比如说子线程在进行读写的时候,主窗体的进度条随着读写的进度在变化。
 读写
 1 public void ReadFileToBuffer()
 2         {
 3             inputStream.BeginRead(buffer, 0, blockSize, WriteFileToBlob, null);//以Begin开头的表示为异步方式,将一块文件读到Buffer里,读完了就调用WriteFileToBlob回调函数
 4         }
 5         public void WriteFileToBlob(IAsyncResult a)
 6         {
 7             inputStream.EndRead(a);//结束读这一线程
 8             if (i < blockCount)//不是最后一块的时候,将Buffer里的数据写到FileContent这个OracleBlob对象里,写完后调用OnEndWrite1回调函数。
 9             {
10                 fileContent.BeginWrite(buffer, 0, blockSize, OnEndWrite1, null);
11 
12             }
13             if (i == blockCount)//最后一块
14             {
15                 fileContent.BeginWrite(buffer, 0, (int)fileSize % blockSize, OnEndWrite2, null);
16             }
17         }
18         private void OnEndWrite1(IAsyncResult a)
19         {
20             OnFileBuffer(new EventArgs());//读一块引发的事件,此处不说
21             fileContent.EndWrite(a);
22             i++;
23             ReadFileToBuffer();
24         }
25         private void OnEndWrite2(IAsyncResult a)
26         {
27             _txn.Commit();//关闭事务流,结束读写
28             OnFileUpdateComplete(new EventArgs());
29         }

      下载就是上传的一个逆过程,上传懂了下载也就会了,此处不再赘述。

     

原文地址:https://www.cnblogs.com/ddan/p/2645127.html