La conversion d'un fichier en tableau d'octets constitue-t-elle le meilleur moyen de sauvegarder TOUT format de fichier sur une colonne binaire de disque ou de base de données?
Donc, si quelqu'un veut enregistrer un fichier .gif ou .doc/.docx ou .pdf, puis-je le convertir en UT8 bytearray et l'enregistrer sous la base de données sous forme de flux d'octets?
Puisqu'il n'est pas mentionné quelle base de données tu veux dire je suppose que SQL Server. La solution ci-dessous fonctionne pour 2005 et 2008.
Vous devez créer un tableau avec VARBINARY(MAX)
comme l'une des colonnes. Dans mon exemple, j'ai créé la table Raporty
avec la colonne RaportPlik
étant la colonne VARBINARY(MAX)
.
Méthode pour mettre file
dans la base de données à partir de 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();
}
}
Cette méthode consiste à extraire file
de la base de données et à l'enregistrer sur 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);
}
}
}
Cette méthode consiste à extraire file
de la base de données et à la placer sous la forme 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;
}
Cette méthode consiste à mettre MemoryStream
dans la base de données:
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;
}
Bonne codage :-)
Bien que vous puissiez stocker des fichiers de cette façon, le logiciel présente des inconvénients importants:
Ce ne sont là que quelques-uns des inconvénients que je peux avoir par cœur. Pour les petits projets, il peut être intéressant de stocker les fichiers de cette manière, mais si vous concevez un logiciel de niveau entreprise, je le déconseille vivement.
Cela dépend vraiment du serveur de base de données.
Par exemple, SQL Server 2008 prend en charge un type de données FILESTREAM
pour exactement cette situation.
Sinon, si vous utilisez un MemoryStream
, il a une méthode ToArray()
qui convertira en un byte[]
- ceci peut être utilisé pour remplir un champ varbinary
..
En confirmant que je pouvais utiliser la réponse publiée par MadBoy et modifiée par Otiel à la fois sur MS SQL Server 2012 et 2014, en plus des versions précédemment répertoriées à l'aide de colonnes varbinary (MAX).
Si vous vous demandez pourquoi vous ne pouvez pas utiliser "Filestream" (indiqué dans une réponse distincte) en tant que type de données dans le concepteur de tables SQL Server ou pourquoi vous ne pouvez pas définir le type de données d'une colonne sur "Filestream" à l'aide de T-SQL, c'est parce que FILESTREAM est un stockage. attribut du type de données varbinary (MAX). Ce n'est pas un type de données en soi.
Consultez ces articles sur la configuration et l'activation de FILESTREAM sur une base de données: 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
Une fois configuré, une colonne varbinary (max) activée pour filestream peut être ajoutée comme suit:
ALTER TABLE TableName
ADD ColumnName varbinary (max) FILESTREAM NULL
ALLER
Je vais décrire la manière dont j'ai stocké les fichiers, dans SQL Server et Oracle. Cela dépend en grande partie de la manière dont vous obtenez le fichier, en premier lieu, quant à la manière dont vous obtiendrez son contenu, et de la base de données que vous utilisez pour le contenu dans lequel vous le stockerez. Ce sont 2 exemples de base de données distincts avec 2 méthodes distinctes pour obtenir le fichier que j'ai utilisé.
SQL Server
Réponse courte: J'ai utilisé une chaîne d'octets en base64 que j'ai convertie en un fichier byte[]
Et que j'ai stockée dans un champ varbinary(max)
.
Longue réponse:
Supposons que vous importez via un site Web, vous utilisez donc un contrôle <input id="myFileControl" type="file" />
Ou React DropZone. Pour obtenir le fichier, vous utilisez une fonction telle que var myFile = document.getElementById("myFileControl")[0];
ou myFile = this.state.files[0];
.
À partir de là, j'obtiendrais la chaîne base64 en utilisant le code ici: Convertir entrée = fichier en tableau d'octets (utiliser la fonction UploadFile2
).
Ensuite, j'obtiendrais cette chaîne, le nom du fichier (myFile.name
) Et taperais (myFile.type
) Dans un objet JSON:
var myJSONObj = {
file: base64string,
name: myFile.name,
type: myFile.type,
}
et postez le fichier sur un serveur MVC à l'aide de XMLHttpRequest, en spécifiant un type de contenu de application/json
: xhr.send(JSON.stringify(myJSONObj);
. Vous devez construire un ViewModel pour le lier avec:
public class MyModel
{
public string file { get; set; }
public string title { get; set; }
public string type { get; set; }
}
et spécifiez [FromBody]MyModel myModelObj
comme paramètre passé en:
[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)
Ensuite, vous pouvez ajouter ceci à cette fonction et l'enregistrer en utilisant 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);
étant la ligne opératoire.
Vous auriez besoin d'un modèle pour représenter la table de base de données:
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; }
}
Cela enregistrera les données dans un champ varbinary(max)
en tant que byte[]
. Name
et Type
étaient nvarchar(250)
et nvarchar(10)
, respectivement. Vous pouvez inclure la taille en l'ajoutant à votre table en tant que int
colonne & MY_ATTACHMENT_TABLE_MODEL
En tant que public int Size { get; set;}
, Puis en ajoutant la ligne tblAtchm.Size = System.Convert.FromBase64String(myModelObj.file).Length;
ci-dessus.
Oracle
Réponse courte: convertissez-le en byte[]
, Attribuez-le à un OracleParameter
, ajoutez-le à votre OracleCommand
et mettez à jour le champ BLOB
de votre table à l'aide d'une référence à la valeur ParameterName
du paramètre: :BlobParameter
Réponse longue: Quand j'ai fait cela pour Oracle, j'utilisais un OpenFileDialog
et j'ai récupéré et envoyé les informations de fichier/octets de cette façon:
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);
}
Et dans la mise à jour Oracle, réalisée avec 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
);
}
}
Et le type de données pour la colonne FILE_CONTENTS
Était BLOB
, le FILE_SIZE
Était NUMBER(10,0)
, LAST_MODIFIED
Était DATE
, et le reste était NVARCHAR2(250)
.
Oui, le meilleur moyen de stocker un fichier dans une base de données consiste généralement à enregistrer le tableau d'octets dans une colonne BLOB. Vous voudrez probablement que quelques colonnes stockent en plus les métadonnées du fichier, telles que le nom, l'extension, etc.
Ce n'est pas toujours une bonne idée de stocker des fichiers dans la base de données. Par exemple, la taille de la base de données augmentera rapidement si vous y stockez des fichiers. Mais tout dépend de votre scénario d'utilisation.
Quelle base de données utilisez-vous? Normalement, vous ne sauvegardez pas les fichiers dans une base de données, mais je pense que SQL 2008 est supporté par celle-ci ...
Un fichier est une donnée binaire, donc UTF 8 n’a aucune importance ici.
UTF 8 est important lorsque vous essayez de convertir une chaîne en un tableau d'octets ... pas un fichier en tableau d'octets.