Ist das Konvertieren einer Datei in ein Byte-Array der beste Weg, um ein beliebiges Dateiformat auf einer binären Spalte der Festplatte oder Datenbank var zu speichern?
Wenn jemand eine .gif- oder .doc / .docx- oder .pdf-Datei speichern möchte, kann ich sie dann einfach in ein Bytearray-UFT8 konvertieren und als Bytestrom in der Datenbank speichern?
Antworten:
Da nicht erwähnt wird, welche Datenbank Sie meinen, gehe ich von SQL Server aus. Die folgende Lösung funktioniert sowohl für 2005 als auch für 2008.
Sie müssen eine Tabelle mit
VARBINARY(MAX)
einer der Spalten erstellen . In meinem Beispiel habe ich eine TabelleRaporty
mit einer SpalteRaportPlik
alsVARBINARY(MAX)
Spalte erstellt.Methode zum Einfügen
file
in die Datenbank vondrive
: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(); } }
Diese Methode dient zum Abrufen
file
aus der Datenbank und zum Speichern aufdrive
: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); } } }
Diese Methode wird
file
aus der Datenbank abgerufen und wie folgt ausgedrücktMemoryStream
: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; }
Diese Methode wird in die
MemoryStream
Datenbank gestellt: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; }
Viel Spaß beim Codieren :-)
quelle
Während Sie Dateien auf diese Weise speichern können, hat dies erhebliche Nachteile:
Dies sind nur einige der Nachteile, die ich mir auf den Kopf stellen kann. Für kleine Projekte kann es sich lohnen, Dateien auf diese Weise zu speichern, aber wenn Sie Software für Unternehmen entwerfen, würde ich dringend davon abraten.
quelle
Es hängt wirklich vom Datenbankserver ab.
Beispielsweise unterstützt SQL Server 2008 einen
FILESTREAM
Datentyp für genau diese Situation.Wenn Sie a verwenden
MemoryStream
, wird eineToArray()
Methode verwendet, die in a konvertiert wird.byte[]
Dies kann zum Auffüllen einesvarbinary
Felds verwendet werden.quelle
Ich werde beschreiben, wie ich Dateien in SQL Server und Oracle gespeichert habe. Es hängt in erster Linie davon ab, wie Sie die Datei erhalten, wie Sie ihren Inhalt erhalten, und es hängt davon ab, welche Datenbank Sie für den Inhalt verwenden, in dem Sie sie speichern, und wie Sie sie speichern. Dies sind 2 separate Datenbankbeispiele mit 2 separaten Methoden zum Abrufen der von mir verwendeten Datei.
SQL Server
Kurze Antwort: Ich habe eine Base64-Byte-Zeichenfolge verwendet, die ich in eine konvertiert
byte[]
und in einemvarbinary(max)
Feld gespeichert habe .Lange Antwort:
Angenommen, Sie laden über eine Website
<input id="myFileControl" type="file" />
hoch , verwenden also ein Steuerelement oder React DropZone. Um die Datei zu erhalten, machen Sie so etwas wievar myFile = document.getElementById("myFileControl")[0];
odermyFile = this.state.files[0];
.Von dort würde ich die base64-Zeichenfolge mit Code hier erhalten: Konvertiere input = file in byte array (benutze Funktion
UploadFile2
).Dann würde ich diesen String, den Dateinamen (
myFile.name
) und den Typ (myFile.type
) in ein JSON-Objekt bekommen:var myJSONObj = { file: base64string, name: myFile.name, type: myFile.type, }
und senden Sie die Datei mit XMLHttpRequest an ein MVC-Server-Backend, wobei Sie einen Inhaltstyp angeben
application/json
:xhr.send(JSON.stringify(myJSONObj);
. Sie müssen ein ViewModel erstellen, um es zu binden:public class MyModel { public string file { get; set; } public string title { get; set; } public string type { get; set; } }
und geben Sie
[FromBody]MyModel myModelObj
als übergebenen Parameter an:[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)
Anschließend können Sie dies zu dieser Funktion hinzufügen und mit Entity Framework speichern:
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);
die operative Linie sein.Sie benötigen ein Modell zur Darstellung der Datenbanktabelle:
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; } }
Dadurch werden die Daten in einem
varbinary(max)
Feld als gespeichertbyte[]
.Name
undType
warennvarchar(250)
undnvarchar(10)
jeweils. Sie können die Größe einschließen, indem Sie sie alsint
Spalte &MY_ATTACHMENT_TABLE_MODEL
as zu Ihrer Tabellepublic int Size { get; set;}
hinzufügen und in dertblAtchm.Size = System.Convert.FromBase64String(myModelObj.file).Length;
obigen Zeile hinzufügen .Orakel
Kurze Antwort: Konvertieren Sie es in a
byte[]
, weisen Sie es einem zuOracleParameter
, fügen Sie es Ihrem hinzuOracleCommand
und aktualisieren Sie dasBLOB
Feld Ihrer Tabelle unter Verwendung eines Verweises auf denParameterName
Wert des Parameters ::BlobParameter
Lange Antwort: Als ich dies für Oracle getan habe, habe ich ein verwendet
OpenFileDialog
und die Bytes / Datei-Informationen auf folgende Weise abgerufen und gesendet: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); }
Und innerhalb des Oracle-Updates, das mit ADO erstellt wurde:
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 ); } }
Und der Datentyp für die
FILE_CONTENTS
Spalte warBLOB
,FILE_SIZE
warNUMBER(10,0)
,LAST_MODIFIED
warDATE
und der Rest warNVARCHAR2(250)
.quelle
Ja, im Allgemeinen ist der beste Weg, eine Datei in einer Datenbank zu speichern, das Speichern des Byte-Arrays in einer BLOB-Spalte. Möglicherweise möchten Sie in einigen Spalten zusätzlich die Metadaten der Datei wie Name, Erweiterung usw. speichern.
Es ist nicht immer eine gute Idee, Dateien in der Datenbank zu speichern. Beispielsweise wächst die Datenbankgröße schnell, wenn Sie Dateien in der Datenbank speichern. Das hängt jedoch alles von Ihrem Nutzungsszenario ab.
quelle
Blob
gilt für Oracle, nicht für SQL Server.Bestätigung, dass ich die von MadBoy gepostete und von Otiel auf MS SQL Server 2012 und 2014 bearbeitete Antwort zusätzlich zu den zuvor mit varbinary (MAX) -Spalten aufgelisteten Versionen verwenden konnte.
Wenn Sie sich fragen, warum Sie im SQL Server-Tabellen-Designer nicht "Datestream" (in einer separaten Antwort angegeben) als Datentyp verwenden können oder warum Sie den Datentyp einer Spalte mit T-SQL nicht auf "Filestream" setzen können, liegt dies daran, dass FILESTREAM ein Speicher ist Attribut des Datentyps varbinary (MAX). Es ist kein Datentyp für sich.
Lesen Sie diese Artikel zum Einrichten und Aktivieren von FILESTREAM in einer Datenbank: 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
Nach der Konfiguration kann eine filestream-fähige varbinary (max) -Spalte wie folgt hinzugefügt werden:
ALTER TABLE TableName
ADD ColumnName varbinary (max) FILESTREAM NULL
GEHEN
quelle
Welche Datenbank verwenden Sie? Normalerweise speichert man keine Dateien in einer Datenbank, aber ich denke, SQL 2008 unterstützt dies ...
Eine Datei besteht aus Binärdaten, daher spielt UTF 8 hier keine Rolle.
UTF 8 ist wichtig, wenn Sie versuchen, eine Zeichenfolge in ein Byte-Array zu konvertieren ... nicht in eine Datei in ein Byte-Array.
quelle