Сохранение любого файла в базе данных, просто преобразовать его в байтовый массив?

Преобразование файла в байтовый массив - лучший способ сохранить ЛЮБОЙ формат файла на двоичный столбец 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

Другие вопросы по тегам