Сохранение любого файла в базе данных, просто преобразовать его в байтовый массив?
Преобразование файла в байтовый массив - лучший способ сохранить ЛЮБОЙ формат файла на двоичный столбец var диска или базы данных?
Так что, если кто-то хочет сохранить файл.gif или.doc /.docx или.pdf, могу ли я просто преобразовать его в байтовый массив UFT8 и сохранить его в БД в виде потока байтов?
8 ответов
Поскольку не указано, какую базу данных вы имеете в виду, я предполагаю 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 2008 с типом столбца FILESTREAM является исключением из правила.)
- Резервное копирование / репликация БД становится чрезвычайно медленным.
- Намного легче справиться с поврежденным диском с 2 миллионами образов - просто замените диск на RAID - чем таблица БД, которая становится поврежденной.
- Если вы случайно удалите дюжину изображений в файловой системе, ваши оперативные работники могут довольно легко заменить их из резервной копии, и, поскольку индекс таблицы по сравнению с ней невелик, его можно быстро восстановить. Если вы случайно удалили дюжину изображений в гигантской таблице базы данных, вам придется долго и мучительно ждать восстановления БД из резервной копии, тем самым парализуя всю вашу систему.
Это лишь некоторые из недостатков, которые я могу придумать. Для крошечных проектов, возможно, стоит хранить файлы таким способом, но если вы разрабатываете программное обеспечение корпоративного уровня, я настоятельно рекомендую против этого.
Это действительно зависит от сервера базы данных.
Например, SQL Server 2008 поддерживает FILESTREAM
тип данных именно для этой ситуации.
Кроме этого, если вы используете MemoryStream
, оно имеет ToArray()
метод, который преобразует в byte[]
- это можно использовать для заполнения varbinary
поле..
Я опишу способ хранения файлов в SQL Server и Oracle. Во многом это зависит от того, как вы получаете файл, в первую очередь от того, как вы получите его содержимое, и от базы данных, которую вы используете для содержимого, в котором вы будете хранить его, и от того, как вы будете его хранить. Это 2 отдельных примера базы данных с 2 отдельными способами получения файла, который я использовал.
SQL Server
Краткий ответ: я использовал байтовую строку base64, которую я преобразовал в byte[]
и хранить в varbinary(max)
поле.
Длинный ответ:
Допустим, вы загружаете через веб-сайт, поэтому вы используете <input id="myFileControl" type="file" />
контроль, или реагировать DropZone. Чтобы получить файл, вы делаете что-то вроде var myFile = document.getElementById("myFileControl")[0];
или же myFile = this.state.files[0];
,
Оттуда я получу строку base64, используя здесь код: Преобразовать ввод = файл в байтовый массив (используйте функцию UploadFile2
).
Тогда я бы получил эту строку, имя файла (myFile.name
) и тип (myFile.type
) в объект JSON:
var myJSONObj = {
file: base64string,
name: myFile.name,
type: myFile.type,
}
и отправьте файл в серверную часть MVC, используя XMLHttpRequest, указав 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
было NUMBER(10,0)
, LAST_MODIFIED
было DATE
а остальные были NVARCHAR2(250)
,
Какую базу данных вы используете? обычно вы не сохраняете файлы в базу данных, но я думаю, что в SQL 2008 есть поддержка...
Файл представляет собой двоичные данные, поэтому UTF 8 здесь не имеет значения.
UTF 8 имеет значение, когда вы пытаетесь преобразовать строку в байтовый массив... а не в файл в байтовый массив.
Подтверждение того, что я смог использовать ответ, опубликованный MadBoy и отредактированный Otiel на MS SQL Server 2012 и 2014 в дополнение к версиям, ранее перечисленным с использованием столбцов varbinary(MAX).
Если вас интересует, почему вы не можете использовать "Файловый поток" (отмеченный в отдельном ответе) в качестве типа данных в конструкторе таблиц 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
ИДТИ
Да, как правило, лучший способ сохранить файл в базе данных - это сохранить массив байтов в столбце BLOB. Возможно, вам понадобится пара столбцов для дополнительного хранения метаданных файла, таких как имя, расширение и т. Д.
Не всегда хорошая идея хранить файлы в базе данных - например, размер базы данных будет быстро расти, если вы храните файлы в ней. Но это все зависит от вашего сценария использования.
Посмотрите на это, возможно, вам будет проще ответить на ваш вопрос
using:
using System.IO;
using System.Data.SqlClient;
code:
private void Form1_Load(object sender, EventArgs e)
{
display();
}
byte[] filebyte = null;
SqlConnection sqlcon = new SqlConnection("Data Source=.;Initial Catalog=test programin;Integrated Security=True");
SqlCommand sqlcmnd = new SqlCommand();
void display ()
{
DataSet dtset = new DataSet();
SqlDataAdapter sqldta = new SqlDataAdapter("select name from tbl_down_up",sqlcon);
sqldta.Fill(dtset, "tbl_down_up");
dataGridView1.DataSource = dtset;
dataGridView1.DataMember = "tbl_down_up";
dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
private void btnup_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "all file|*.*";
if(ofd.ShowDialog()==DialogResult.OK)
{
FileStream fs = new FileStream(ofd.FileName, FileMode.Open);
MemoryStream ms = new MemoryStream();
fs.CopyTo(ms);
filebyte = ms.ToArray();
string[] filename = ofd.FileName.Split('\\');
sqlcmnd = new SqlCommand("insert into tbl_down_up(name,data)values(@name,@data)",sqlcon);
sqlcmnd.Parameters.AddWithValue("@name",filename[filename.Length-1]);
sqlcmnd.Parameters.AddWithValue("@data",SqlDbType.VarBinary).Value=filebyte;
sqlcon.Open();
sqlcmnd.ExecuteNonQuery();
sqlcon.Close();
sqlcmnd.Parameters.Clear();
display();
}
}
private void btndown_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
string[] filename = dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString().Split('.');
sfd.Filter = "type file " + filename[filename.Length - 1] + " |*." + filename[filename.Length - 1];
sfd.FileName = dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString();
if (sfd.ShowDialog() == DialogResult.OK)
{
FileStream fs = new FileStream(sfd.FileName, FileMode.Create);
sqlcmnd = new SqlCommand("select data from tbl_down_up where name ='"+dataGridView1[0,dataGridView1.CurrentRow.Index].Value.ToString()+"'", sqlcon);sqlcon.Open();
SqlDataReader dr = sqlcmnd.ExecuteReader();
while (dr.Read())
{
filebyte = (byte[])dr[0];
}
sqlcon.Close();
fs.Write(filebyte, 0, filebyte.Length);
fs.Close();
display();
}
}
private void btndel_Click(object sender, EventArgs e)
{
sqlcmnd = new SqlCommand("delete from tbl_down_up where name =N'" + dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString() + "'", sqlcon);
sqlcon.Open();
sqlcmnd.ExecuteNonQuery();
sqlcon.Close();
display();
}
video for form:
form1
image for tbl_down_up sqlserver:
tbl_down_up