将文件转换为字节数组是将任何文件格式保存到磁盘或数据库var二进制列的最佳方法吗?
因此,如果有人要保存.gif或.doc / .docx或.pdf文件,是否可以将其转换为UFT8字节数组并将其作为字节流保存到db中?
Answers:
由于未提及您指的是什么数据库,因此我假设使用SQL Server。以下解决方案适用于2005年和2008年。
您必须使用VARBINARY(MAX)
列之一创建表。在我的例子,我创建的表Raporty
与列RaportPlik
之中VARBINARY(MAX)
列。
file
从drive
以下方法放入数据库的方法:
public static void databaseFilePut(string varFilePath) {
byte[] file;
using (var stream = new FileStream(varFilePath, FileMode.Open, FileAccess.Read)) {
using (var reader = new BinaryReader(stream)) {
file = reader.ReadBytes((int) stream.Length);
}
}
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlWrite = new SqlCommand("INSERT INTO Raporty (RaportPlik) Values(@File)", varConnection)) {
sqlWrite.Parameters.Add("@File", SqlDbType.VarBinary, file.Length).Value = file;
sqlWrite.ExecuteNonQuery();
}
}
此方法是file
从数据库获取并将其保存在drive
:
public static void databaseFileRead(string varID, string varPathToNewLocation) {
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(@"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = @varID", varConnection)) {
sqlQuery.Parameters.AddWithValue("@varID", varID);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
sqlQueryResult.Read();
var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
using (var fs = new FileStream(varPathToNewLocation, FileMode.Create, FileAccess.Write))
fs.Write(blob, 0, blob.Length);
}
}
}
该方法是file
从数据库获取并将其表示为MemoryStream
:
public static MemoryStream databaseFileRead(string varID) {
MemoryStream memoryStream = new MemoryStream();
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(@"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = @varID", varConnection)) {
sqlQuery.Parameters.AddWithValue("@varID", varID);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
sqlQueryResult.Read();
var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
//using (var fs = new MemoryStream(memoryStream, FileMode.Create, FileAccess.Write)) {
memoryStream.Write(blob, 0, blob.Length);
//}
}
}
return memoryStream;
}
该方法要放入MemoryStream
数据库中:
public static int databaseFilePut(MemoryStream fileToPut) {
int varID = 0;
byte[] file = fileToPut.ToArray();
const string preparedCommand = @"
INSERT INTO [dbo].[Raporty]
([RaportPlik])
VALUES
(@File)
SELECT [RaportID] FROM [dbo].[Raporty]
WHERE [RaportID] = SCOPE_IDENTITY()
";
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) {
sqlWrite.Parameters.Add("@File", SqlDbType.VarBinary, file.Length).Value = file;
using (var sqlWriteQuery = sqlWrite.ExecuteReader())
while (sqlWriteQuery != null && sqlWriteQuery.Read()) {
varID = sqlWriteQuery["RaportID"] is int ? (int) sqlWriteQuery["RaportID"] : 0;
}
}
return varID;
}
快乐编码:-)
尽管您可以用这种方式存储文件,但它有很多折衷:
这些只是我可以克服的一些缺点。对于小型项目,可能值得以这种方式存储文件,但是如果您要设计企业级软件,我强烈建议您反对使用它。
它实际上取决于数据库服务器。
例如,SQL Server 2008FILESTREAM
正是针对这种情况支持数据类型。
除此之外,如果您使用MemoryStream
,则它具有ToArray()
将转换为byte[]
-的方法,该方法可用于填充varbinary
字段。
我将描述在SQL Server和Oracle中存储文件的方式。首先,它主要取决于如何获取文件的内容,以及取决于要使用哪个数据库存储内容以及如何存储文件。这些是2个单独的数据库示例,具有2个获取我使用的文件的单独方法。
SQL服务器
简短的答案:我使用了我转换为a的base64字节字符串,byte[]
并将其存储在varbinary(max)
字段中。
长答案:
假设您是通过网站上传的,那么您正在使用<input id="myFileControl" type="file" />
控件或React DropZone。要获取文件,您正在执行类似var myFile = document.getElementById("myFileControl")[0];
或的操作myFile = this.state.files[0];
。
从那里,我将在此处使用代码获取base64字符串:将input = file转换为字节数组 (使用function UploadFile2
)。
然后,我将得到该字符串,文件名(myFile.name
)并myFile.type
在JSON对象中键入():
var myJSONObj = {
file: base64string,
name: myFile.name,
type: myFile.type,
}
并使用XMLHttpRequest将文件发布到MVC服务器后端,并指定Content-Type为application/json
: xhr.send(JSON.stringify(myJSONObj);
。您必须构建一个ViewModel来绑定它:
public class MyModel
{
public string file { get; set; }
public string title { get; set; }
public string type { get; set; }
}
并指定[FromBody]MyModel myModelObj
为传入的参数:
[System.Web.Http.HttpPost] // required to spell it out like this if using ApiController, or it will default to System.Mvc.Http.HttpPost
public virtual ActionResult Post([FromBody]MyModel myModelObj)
然后,您可以将其添加到该函数中并使用Entity Framework进行保存:
MY_ATTACHMENT_TABLE_MODEL tblAtchm = new MY_ATTACHMENT_TABLE_MODEL();
tblAtchm.Name = myModelObj.name;
tblAtchm.Type = myModelObj.type;
tblAtchm.File = System.Convert.FromBase64String(myModelObj.file);
EntityFrameworkContextName ef = new EntityFrameworkContextName();
ef.MY_ATTACHMENT_TABLE_MODEL.Add(tblAtchm);
ef.SaveChanges();
tblAtchm.File = System.Convert.FromBase64String(myModelObj.file);
作为手术线。
您将需要一个模型来表示数据库表:
public class MY_ATTACHMENT_TABLE_MODEL
{
[Key]
public byte[] File { get; set; } // notice this change
public string Name { get; set; }
public string Type { get; set; }
}
这会将数据另存为一个varbinary(max)
字段byte[]
。 Name
和Type
分别为nvarchar(250)
和nvarchar(10)
。您可以通过将尺寸作为int
列添加为表格来添加尺寸,并MY_ATTACHMENT_TABLE_MODEL
作为public int Size { get; set;}
,然后在tblAtchm.Size = System.Convert.FromBase64String(myModelObj.file).Length;
上面的行中添加尺寸。
甲骨文
简短的答案:将其转换为byte[]
,将其分配给,将其OracleParameter
添加到中OracleCommand
,并BLOB
使用对参数ParameterName
值的引用来更新表的字段::BlobParameter
长答案:当我为Oracle执行此操作时,我使用,OpenFileDialog
然后以这种方式检索并发送字节/文件信息:
byte[] array;
OracleParameter param = new OracleParameter();
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "Image Files (*.jpg, *.jpeg, *.jpe)|*.jpg;*.jpeg;*.jpe|Document Files (*.doc, *.docx, *.pdf)|*.doc;*.docx;*.pdf"
if (dlg.ShowDialog().Value == true)
{
string fileName = dlg.FileName;
using (FileStream fs = File.OpenRead(fileName)
{
array = new byte[fs.Length];
using (BinaryReader binReader = new BinaryReader(fs))
{
array = binReader.ReadBytes((int)fs.Length);
}
// Create an OracleParameter to transmit the Blob
param.OracleDbType = OracleDbType.Blob;
param.ParameterName = "BlobParameter";
param.Value = array; // <-- file bytes are here
}
fileName = fileName.Split('\\')[fileName.Split('\\').Length-1]; // gets last segment of the whole path to just get the name
string fileType = fileName.Split('.')[1];
if (fileType == "doc" || fileType == "docx" || fileType == "pdf")
fileType = "application\\" + fileType;
else
fileType = "image\\" + fileType;
// SQL string containing reference to BlobParameter named above
string sql = String.Format("INSERT INTO YOUR_TABLE (FILE_NAME, FILE_TYPE, FILE_SIZE, FILE_CONTENTS, LAST_MODIFIED) VALUES ('{0}','{1}',{2},:BlobParamerter, SYSDATE)", fileName, fileType, array.Length);
// Do Oracle Update
RunCommand(sql, param);
}
在Oracle更新中,使用ADO完成:
public void RunCommand(string sql, OracleParameter param)
{
OracleConnection oraConn = null;
OracleCommand oraCmd = null;
try
{
string connString = GetConnString();
oraConn = OracleConnection(connString);
using (oraConn)
{
if (OraConnection.State == ConnectionState.Open)
OraConnection.Close();
OraConnection.Open();
oraCmd = new OracleCommand(strSQL, oraConnection);
// Add your OracleParameter
if (param != null)
OraCommand.Parameters.Add(param);
// Execute the command
OraCommand.ExecuteNonQuery();
}
}
catch (OracleException err)
{
// handle exception
}
finally
{
OraConnction.Close();
}
}
private string GetConnString()
{
string host = System.Configuration.ConfigurationManager.AppSettings["host"].ToString();
string port = System.Configuration.ConfigurationManager.AppSettings["port"].ToString();
string serviceName = System.Configuration.ConfigurationManager.AppSettings["svcName"].ToString();
string schemaName = System.Configuration.ConfigurationManager.AppSettings["schemaName"].ToString();
string pword = System.Configuration.ConfigurationManager.AppSettings["pword"].ToString(); // hopefully encrypted
if (String.IsNullOrEmpty(host) || String.IsNullOrEmpty(port) || String.IsNullOrEmpty(serviceName) || String.IsNullOrEmpty(schemaName) || String.IsNullOrEmpty(pword))
{
return "Missing Param";
}
else
{
pword = decodePassword(pword); // decrypt here
return String.Format(
"Data Source=(DESCRIPTION =(ADDRESS = ( PROTOCOL = TCP)(HOST = {2})(PORT = {3}))(CONNECT_DATA =(SID = {4})));User Id={0};Password={1};",
user,
pword,
host,
port,
serviceName
);
}
}
该FILE_CONTENTS
列的数据类型为BLOB
,FILE_SIZE
was NUMBER(10,0)
,LAST_MODIFIED
was DATE
,其余为NVARCHAR2(250)
。
是的,通常在数据库中存储文件的最佳方法是将字节数组保存在BLOB列中。您可能需要两列来另外存储文件的元数据,例如名称,扩展名等。
将文件存储在数据库中并非总是一个好主意-例如,如果您将文件存储在数据库中,则数据库大小将快速增长。但这一切都取决于您的使用情况。
Blob
适用于Oracle,不适用于SQL Server。
确认除了先前使用varbinary(MAX)列列出的版本之外,我还可以使用由MadBoy发布并由Otiel在MS SQL Server 2012和2014上编辑的答案。
如果您想知道为什么不能在SQL Server表设计器中将“文件流”(在单独的答案中注明)作为数据类型,或者为什么不能使用T-SQL将列的数据类型设置为“文件流”,那是因为FILESTREAM是存储设备varbinary(MAX)数据类型的属性。它本身不是数据类型。
请参阅以下有关在数据库上设置和启用FILESTREAM的文章:https : //msdn.microsoft.com/en-us/library/cc645923(v= sql.120).aspx
http://www.kodyaz.com/t-sql/default-filestream-filegroup-is-not-available-in-database.aspx
配置完成后,可以这样添加启用了文件流的varbinary(max)列:
ALTER TABLE TableName
ADD的ColumnName varbinary(max)FILESTREAM NULL
走