c# 操作文件存入数据库(以二进制形式存入)

  在开发的过程中,经常会遇到将文件存入数据库的形式,一般常用方法是将文件上传至服务器,数据库只需保存文件路径地址即可,但是很多内部window应用并不链接网络都是本地运行服务,那么此时我们存储文件就需要用到另一种形式,即将文件 FileStream 操作文件流的形式将文件转为字节存入数据库,下载时,在对应转换下载即可。

 

  本次,我们将提供两种数据库的操作方式,PostgresSql 和 Sqlite 两种数据库的存储方式。

 

  PostgresSql

  Psql 数据库提供了存储字节的类型,即 bytea,所以创建数据库时,要将对应的字段设置为 bytea

1 CREATE TABLE tb_flypath 
2 (  
3     ID SERIAL PRIMARY KEY ,
4     FileName TEXT NOT NULL,
5     FileContent bytea NOT NULL,
6     CreateTime timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP
7 )

  那么,设置为 bytea 后就可以将文件转为字节进行存储了,使用以下代码

 1         /// <summary>
 2         /// 将文件转为字节
 3         /// </summary>
 4         /// <param name="path">文件路径</param>
 5         /// <returns></returns>
 6         public byte[] getContent(string path)
 7         {
 8             System.IO.FileStream fs = new System.IO.FileStream(@path, System.IO.FileMode.Open);
 9             fs.Position = 0;
10             byte[] content = new byte[fs.Length];
11             fs.Read(content, 0, (int)fs.Length);
12             fs.Close();
13             return content;
14         }

  我们直接使用 SQL 语句,将字节转为字符串存入数据库

 1         /// <summary>
 2         /// 字节转字符串
 3         /// </summary>
 4         /// <param name="inputBytes">字节</param>
 5         /// <returns></returns>
 6         public string ByteToString(byte[] inputBytes)
 7         {
 8             StringBuilder temp = new StringBuilder(2048);
 9             foreach (byte tempByte in inputBytes)
10             {
11                 temp.Append(tempByte > 15 ?
12                 Convert.ToString(tempByte, 2) : '0' + Convert.ToString(tempByte, 2));
13             }
14             return temp.ToString();
15         }
16 
17         string bstr = ByteToString(buffer);
18         string insertSql = string.Format(@"INSERT INTO tb_flyPath (FileContent) VALUES ('{0}')", bstr);

  以上就是将文件写入数据库的操作,但是,如果采用此方法的话,就会有问题,因为 INSERT SQL 无法识别字节的类型,所以我们是将字符串存入了对应字节类型的字段里。

  那么后续遇到的问题是,下载文件时,无论如何转换 FileContent 都无法将下载的文件打开,如果是文本的话,则出现的内容为已转换的二进制数据。

  至于为什么会出现这样,还没研究透,欢迎留言。

  所以,我又采取了以下的方式进行数据存储,使用数据库 Parameter 参数执行SQL,这种方法可以将你传入的数据直接转为对应的类型  DbType.Bytea ,此类型可以传入字节类型数据进行存储,使用这种方式后,存入的数据就可以下载后进行转换使用并打开各种文件了。

 1         /// <summary>
 2         /// 文件存储入表
 3         /// </summary>
 4         /// <param name="filePath">文件路径</param>
 5         /// <param name="id">节点ID</param>
 6         /// <returns></returns>
 7         public bool FileInsert(string filePath, string id)
 8         {
 9             string strErrMsg = "";
10             //读取文件 
11             FileStream fs = File.OpenRead(filePath);
12             byte[] buffer = new byte[fs.Length];
13             fs.Read(buffer, 0, buffer.Length);
14 
15             if (!CreateCommand(out strErrMsg))
16                 return false;
17 
31             NpgsqlParameter paramFileContent = _Command.CreateParameter();
32             paramFileContent.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Bytea;
33             paramFileContent.ParameterName = "FileContent";
34             paramFileContent.Direction = ParameterDirection.Input;
35             paramFileContent.Value = buffer;
36             _Command.Parameters.Add(paramFileContent);
37 
38             NpgsqlParameter paramFileName = _Command.CreateParameter();
39             paramFileName.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar;
40             paramFileName.ParameterName = "FileName";
41             paramFileName.Direction = ParameterDirection.Input;
42             paramFileName.Value = id;
43             _Command.Parameters.Add(paramFileName);
44 
45             string sqlInsert = "INSERT INTO tb_flypath (filename,filecontent) VALUES (:FileName, :FileContent)";
46             _Command.CommandText = sqlInsert;
47             _Command.CommandType = CommandType.Text;
48 
49             _Connection.Open();
50             int result = _Command.ExecuteNonQuery();
51             _Connection.Close();
52 
53             return result > 0 ? true : false;
54         }
55 
56         /// <summary> 
57         /// 根据文件名从数据库中获取文件 
58         /// </summary> 
59         /// <param name="fileName">数据库中的文件名</param> 
60         /// <param name="savePath">文件的保存路径,包括文件名,如D:\test.fly</param> 
61         public bool DownloadFile(string fileName, string savePath)
62         {
63             string strErrMsg = "";
64 
65             if (!CreateCommand(out strErrMsg))
66                 return false;70 
71             string sqlSelect = "select filename, filecontent from tb_flypath where filename=:FileName";
72             _Command.CommandText = sqlSelect;
73             _Command.CommandType = CommandType.Text;
74 
75             NpgsqlParameter paramFileName = _Command.CreateParameter();
76             paramFileName.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar;
77             paramFileName.ParameterName = "FileName";
78             paramFileName.Direction = ParameterDirection.Input;
79             paramFileName.Value = fileName;
80             _Command.Parameters.Add(paramFileName);
81 
82             _Connection.Open();
83             NpgsqlDataReader dr = _Command.ExecuteReader();
84             dr.Read();
85             byte[] buffer = (byte[])dr["filecontent"];
86             dr.Close();
87             _Connection.Close();
88 
89             //把文件保存到指定路径 
90             File.WriteAllBytes(savePath, buffer);
91 
92             return true;
93         }

 

  Sqlite

  我们在讲下 Sqlite 数据库的操作方式,其实方法都一样,没什么太大区别,只是各个数据库的存储数据类型不太一样。

  Sqlite 提供了 BLOB 类型进行存储字节数据,所以创建表。

1 CREATE TABLE tb_flyPath
2 (
3     ID INTEGER primary key autoincrement , 
4     FileName VARCHAR not null ,
5     FileContent BLOB not null ,
6     CreateTime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
7 )

  那么存取文件的方法大致无区别,PostgresSql 用的是 bytea 类型,那么 Sqlite 这里需要设置为 DbType.Binary 类型。

 1         /// <summary>
 2         /// 文件存储入表
 3         /// </summary>
 4         /// <param name="filePath">文件路径</param>
 5         /// <param name="id">节点ID</param>
 6         /// <returns></returns>
 7         public bool FileInsert(string filePath, string id)
 8         {
 9             string strErrMsg = "";
10             //读取文件 
11             FileStream fs = File.OpenRead(filePath);
12             byte[] buffer = new byte[fs.Length];
13             fs.Read(buffer, 0, buffer.Length);
14 
15             if (!CreateCommand(out strErrMsg))
16                 return false;
17 
31             SQLiteParameter paramFileContent = _Command.CreateParameter();
32             paramFileContent.DbType = DbType.Binary;
33             paramFileContent.ParameterName = "FileContent";
34             paramFileContent.Direction = ParameterDirection.Input;
35             paramFileContent.Value = buffer;
36             _Command.Parameters.Add(paramFileContent);
37 
38             SQLiteParameter paramFileName = _Command.CreateParameter();
39             paramFileName.DbType = DbType.String;
40             paramFileName.ParameterName = "FileName";
41             paramFileName.Direction = ParameterDirection.Input;
42             paramFileName.Value = id;
43             _Command.Parameters.Add(paramFileName);
44 
45             string sqlInsert = "INSERT INTO tb_flyPath (filename,filecontent) VALUES (:FileName, :FileContent)";
46             _Command.CommandText = sqlInsert;
47             _Command.CommandType = CommandType.Text;
48 
49             _Connection.Open();
50             int result = _Command.ExecuteNonQuery();
51             _Connection.Close();
52 
53             return result > 0 ? true : false;
54         }
55 
56         /// <summary> 
57         /// 根据文件名从数据库中获取文件 
58         /// </summary> 
59         /// <param name="fileName">数据库中的文件名</param> 
60         /// <param name="savePath">文件的保存路径,包括文件名,如D:\test.fly</param> 
61         public bool DownloadFile(string fileName, string savePath)
62         {
63             string strErrMsg = "";
64 
65             if (!CreateCommand(out strErrMsg))
66                 return false;
67 
71             string sqlSelect = "select filename, filecontent from tb_flyPath where filename=:FileName";
72             _Command.CommandText = sqlSelect;
73             _Command.CommandType = CommandType.Text;
74 
75             SQLiteParameter paramFileName = _Command.CreateParameter();
76             paramFileName.DbType = DbType.String;
77             paramFileName.ParameterName = "FileName";
78             paramFileName.Direction = ParameterDirection.Input;
79             paramFileName.Value = fileName;
80             _Command.Parameters.Add(paramFileName);
81 
82             _Connection.Open();
83             SQLiteDataReader dr = _Command.ExecuteReader();
84             dr.Read();
85             byte[] buffer = (byte[])dr["filecontent"];
86             dr.Close();
87             _Connection.Close();
88 
89             //把文件保存到指定路径 
90             File.WriteAllBytes(savePath, buffer);
91 
92             return true;
93         }

 

  如有讲的不对,欢迎评论留言。

posted @ 2022-01-20 10:57  object0812  阅读(3742)  评论(0编辑  收藏  举报