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 }
如有讲的不对,欢迎评论留言。