El petit hashejador ha rebut queixes del seu usuari principal, jo, i clar el desenvolupador ha tingut que fer-li cas, jo mateix. Així que l'he afegit algunes funcionalitats més.
"crea path [-r] [-desde_cero]:" crea un fitxer XML amb els Hash dels fitxers. -r indica recursiu. -desde_cero: esborra els fitxers de hashos existents. Si no es posa aquesta opció si ja existeix el fitxeret de hashos es salta la carpeta.
"verifica path [-r] [-continua]" verifica que els fitxers tinguin el Hash correcte, -r indica recursiu, -continua no verifica els fitxers en estat VERIFICAT. Clar hem vaig trobar que el procés de verificació de moooolts fitxers triga, i volia un procés que pugui ser interromput i que continuï des d'on ho va deixar en un altra moment. La verificació guarda el fitxer de hashos cada 5GB de fitxers processat i quan acaba de verificar la carpeta.
"resultats path [-r]" no calcula hashos, llegeix els fitxers del hasher buscant fitxers amb modificacions, errors i esborrats. -r indica recursiu. Si deixes la finestra amb el verifica fent, clar, potser et perds els errors o algo. Aleshores el resultats els ensenya.
"actualitza path [-r]" calcula hashos per fitxers nous, esborra del fitxer de hashos els que pertanyen a fitxers esborrats, -r indica recursiu.
"reset path [-r]" reseteja l'estat a PENDENT, -r indica recursiu. Clar, el verifica posa l'estat del fitxer a "VERIFICAT", cal doncs alguna forma de tornar a començar sense crear el fitxer de cero. Així es poden llançar verificacions en diferents dies. Primer un "reset" i després un "verifica".
Com sempre el codi, primer l'aplicació de consola, després la clase:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace Hasher
{
classProgram
{
privatestaticstring ExecutablePath = "";
privatestaticstring CarpetaAProcessar = "";
privatestaticbool Recursiu = false;
privatestaticbool Creacio_de_cero = false;
privatestaticstring Accio = "";
privatestaticbool Continua = false;
staticvoid Main(string[] args)
{
string AppPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
ExecutablePath = Path.GetDirectoryName(AppPath);
try
{
if (args.Length > 0)
{
ParseParams(args);
if (CarpetaAProcessar != "")
{
if (!Directory.Exists(CarpetaAProcessar))
{
Console.WriteLine("Carpeta no trobada: " + CarpetaAProcessar);
return;
}
}
else
{
Console.WriteLine("Carpeta a processar no informada");
return;
}
switch (Accio)
{
case"crea":
crea(CarpetaAProcessar);
Console.WriteLine(ObtenirData() + " - creació acabada.");
break;
case"verifica":
verifica(CarpetaAProcessar);
Console.WriteLine(ObtenirData() + " - verificació acabada.");
break;
case"resultats":
resultats(CarpetaAProcessar);
Console.WriteLine(ObtenirData() + " - obtenir resultats acabat.");
break;
case"actualitza":
actualitza(CarpetaAProcessar);
Console.WriteLine(ObtenirData() + " - actualitza acabat.");
break;
case"reset":
reset(CarpetaAProcessar);
Console.WriteLine(ObtenirData() + " - reset acabat.");
break;
default:
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r] [-desde_cero]\" crea un fitxer XML amb els Hash dels fitxers. "
+ "-r indica recursiu. -desde_cero: esborra els fitxers de hashos existents.");
Console.WriteLine("\"verifica path [-r] [-continua]\" verifica que els fitxers tinguin el Hash correcte, "
+ "-r indica recursiu, -continua no verifica els fitxers en estat VERIFICAT");
Console.WriteLine("\"resultats path [-r]\" no calcula hashos, llegeix els fitxers del hasher buscant "
+ " fitxers amb modificacions, -r indica recursiu");
Console.WriteLine("\"actualitza path [-r]\" calcula hashos per fitxers nous, "
+ "esborra del fitxer de hashos els que pertanyen a fitxers esborrats, -r indica recursiu");
Console.WriteLine("\"reset path [-r]\" reseteja l'estat a PENDENT, -r indica recursiu");
break;
}
}
else
{
Console.WriteLine("Possibles parametres:");
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r] [-desde_cero]\" crea un fitxer XML amb els Hash dels fitxers. "
+ "-r indica recursiu. -desde_cero: esborra els fitxers de hashos existents.");
Console.WriteLine("\"verifica path [-r] [-continua]\" verifica que els fitxers tinguin el Hash correcte, "
+ "-r indica recursiu, -continua no verifica els fitxers en estat VERIFICAT");
Console.WriteLine("\"resultats path [-r]\" no calcula hashos, llegeix els fitxers del hasher buscant "
+ " fitxers amb modificacions, -r indica recursiu");
Console.WriteLine("\"actualitza path [-r]\" calcula hashos per fitxers nous, "
+ "esborra del fitxer de hashos els que pertanyen a fitxers esborrats, -r indica recursiu");
Console.WriteLine("\"reset path [-r]\" reseteja l'estat a PENDENT, -r indica recursiu");
}
}
catch(Exception Err)
{
Console.WriteLine(Err.Source + " - " + Err.TargetSite + "-" + Err.Message);
}
}
privatestaticvoid reset(string pPath)
{
if (!File.Exists(pPath + "\\hasher.xml"))
{
Console.WriteLine(ObtenirData() + " - No hi ha fitxer de hashos: " + pPath);
}
else
{
Dictionary<string, clsFitxer> DicFitxers;
DicFitxers = CarregaHashos(pPath);
Console.WriteLine(ObtenirData() + " - resetejant: " + pPath);
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
objFitxer.Value.Estat = "PENDENT";
}
Save(pPath, DicFitxers);
}
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
reset(Carpeta);
}
}
}
publicstaticstring SHA256HashFile(string sPath)
{
string sHash = "";
using (var stream = new BufferedStream(File.OpenRead(sPath), 2400000))
{
SHA256CryptoServiceProvider sha256h = new SHA256CryptoServiceProvider();
sHash = BitConverter.ToString(sha256h.ComputeHash(stream));
}
return sHash;
}
privatestaticvoid actualitza(string pPath)
{
if (!File.Exists(pPath + "\\hasher.xml"))
{
Console.WriteLine(ObtenirData() + " - No hi ha fitxer de hashos: " + pPath);
}
else
{
Dictionary<string, clsFitxer> DicFitxers;
Dictionary<string, clsFitxer> FitxersActualitzats = newDictionary<string, clsFitxer>();
clsFitxer FitxerActualitzat = null;
DicFitxers = CarregaHashos(pPath);
DirectoryInfo dir = newDirectoryInfo(pPath);
FileInfo[] Fitxers = dir.GetFiles();
Console.WriteLine(ObtenirData() + " - Processant " + pPath);
//Comprovar que tots els fitxers del fitxer de hashos estan al disc, treure els que no estanforeach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
try
{
if (File.Exists(pPath + "\\ " + objFitxer.Value.Nom))
{
FitxerActualitzat = new clsFitxer(objFitxer.Value.Nom,
objFitxer.Value.DataCreacio,
objFitxer.Value.DataVerificacio,
objFitxer.Value.MidaEnBytes,
objFitxer.Value.Hash,
objFitxer.Value.Estat);
FitxersActualitzats.Add(FitxerActualitzat.Nom, FitxerActualitzat);
}
}
catch (IOException e)
{
Console.WriteLine("I/O Exception: " + e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("Access Exception: " + e.Message);
}
}
//Comprovar que els fitxers de la carpeta estan, afegir els nousforeach (FileInfo Fitxer in Fitxers)
{
if (!DicFitxers.ContainsKey(Fitxer.Name))
{
if (Fitxer.Name.ToLower() != "hasher.exe" && Fitxer.Name.ToLower() != "hasher.xml")
{
string hashValueStr = SHA256HashFile(Fitxer.FullName);
Console.WriteLine(ObtenirData() + " - hashejat: " + Fitxer.Name);
FitxerActualitzat = new clsFitxer(Fitxer.Name, DateTime.Now,
DateTime.Now,
Fitxer.Length,
hashValueStr,
"CREAT");
FitxersActualitzats.Add(Fitxer.Name, FitxerActualitzat);
}
}
}
Save(pPath, FitxersActualitzats);
}
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
actualitza(Carpeta);
}
}
}
privatestaticvoid ParseParams(string[] args)
{
for(int i = 0; i<args.Length; i++)
{
if(args[i].ToLower() == "crea")
{
Accio = "crea";
}
if (args[i].ToLower() == "verifica")
{
Accio = "verifica";
}
if (args[i].ToLower() == "resultats")
{
Accio = "resultats";
}
if (args[i].ToLower() == "actualitza")
{
Accio = "actualitza";
}
if (args[i].ToLower() == "reset")
{
Accio = "reset";
}
if (args[i].ToLower() == "-r")
{
Recursiu = true;
}
if (args[i].ToLower() == "-desde_cero")
{
Creacio_de_cero = true;
}
if (args[i].ToLower() == "-continua")
{
Continua = true;
}
if(args[i].Contains(":"))
{
CarpetaAProcessar = args[i].Replace("\\\\ ", "\\ ");
}
}
}
privatestaticvoid resultats(string pPath)
{
if (!File.Exists(pPath + "\\hasher.xml"))
{
Console.WriteLine(ObtenirData() + " - No hi ha fitxer de hashos: " + pPath);
}
else
{
Dictionary<string, clsFitxer> DicFitxers;
DicFitxers = CarregaHashos(pPath);
Console.WriteLine(ObtenirData() + " - analitzant: " + pPath);
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
if(objFitxer.Value.Estat == "NO COINCIDEIX")
{
Console.WriteLine(ObtenirData(objFitxer.Value.DataVerificacio)
+ " - fitxer amb hash canviat: " + pPath + "\\ " + objFitxer.Value.Nom);
}
else
{
if(objFitxer.Value.Estat.Contains("MIDA DIFERENT"))
{
Console.WriteLine(ObtenirData(objFitxer.Value.DataVerificacio)
+ " - fitxer amb mida diferent: " + pPath + "\\ " + objFitxer.Value.Nom);
}
else
{
if (objFitxer.Value.Estat == "ESBORRAT")
{
Console.WriteLine(ObtenirData(objFitxer.Value.DataVerificacio)
+ " - fitxer esborrat: " + pPath + "\\ " + objFitxer.Value.Nom);
}
}
}
}
}
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
resultats(Carpeta);
}
}
}
publicstaticstring ObtenirData(DateTime data)
{
return data.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
publicstaticstring ObtenirData()
{
returnDateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
publicstaticvoid verifica(string pPath)
{
long GBHashejats = 0;
Console.WriteLine(ObtenirData() + " - verificant carpeta: " + pPath);
if (!File.Exists(pPath + "\\hasher.xml"))
{
Console.WriteLine(ObtenirData() + " - No hi ha fitxer de hashos: " + pPath);
}
else
{
Dictionary<string, clsFitxer> DicFitxers;
DicFitxers = CarregaHashos(pPath);
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
if (objFitxer.Value.Estat == "VERIFICAT" && Continua)
{
Console.WriteLine(ObtenirData() + " - fitxer ja verificat anteriorment: " + objFitxer.Value.Nom);
}
else
{
try
{
if (File.Exists(pPath + "\\ " + objFitxer.Value.Nom))
{
FileInfo fiFitxer = newFileInfo(pPath + "\\ " + objFitxer.Value.Nom);
if (fiFitxer.Length != objFitxer.Value.MidaEnBytes)
{
Console.WriteLine(ObtenirData() + " - Fitxer amb mida diferent: " + fiFitxer.Name);
objFitxer.Value.Estat = "MIDA DIFERENT, actual: " + fiFitxer.Length;
}
else
{
GBHashejats += fiFitxer.Length;
string hashValueStr = SHA256HashFile(fiFitxer.FullName);
if (hashValueStr == objFitxer.Value.Hash)
{
objFitxer.Value.Estat = "VERIFICAT";
}
else
{
Console.WriteLine(ObtenirData() + " - Fitxer amb hash canviat: " + fiFitxer.Name);
objFitxer.Value.Estat = "NO COINCIDEIX";
}
if(GBHashejats > 5368709120) //5 GB
{
GBHashejats = 0;
Save(pPath, DicFitxers);
}
}
}
else
{
Console.WriteLine(ObtenirData() + " - Fitxer esborrat: " + objFitxer.Value.Nom);
objFitxer.Value.Estat = "ESBORRAT";
}
objFitxer.Value.DataVerificacio = DateTime.Now;
}
catch (IOException e)
{
Console.WriteLine("I/O Exception: " + e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("Access Exception: " + e.Message);
}
}
}
Save(pPath, DicFitxers);
}
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach(string Carpeta in Carpetes)
{
verifica(Carpeta);
}
}
}
publicstaticDictionary<string, clsFitxer> CarregaHashos(string pPath)
{
XmlDocument Doc = newXmlDocument();
XmlNode Fitxers;
XmlNodeList llistaDeFitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = newDictionary<string, clsFitxer>();
Doc.Load(pPath + "\\hasher.xml");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
llistaDeFitxer = Fitxers.ChildNodes;
foreach (XmlNode Fitxer in llistaDeFitxer)
{
objFitxer = new clsFitxer();
Nom = Fitxer.SelectSingleNode("descendant::nom");
Hash = Fitxer.SelectSingleNode("descendant::hash");
DataCreacio = Fitxer.SelectSingleNode("descendant::datacreacio");
DataVerificacio = Fitxer.SelectSingleNode("descendant::dataverificacio");
Estat = Fitxer.SelectSingleNode("descendant::estat");
MidaEnBytes = Fitxer.SelectSingleNode("descendant::midaenbytes");
objFitxer.Nom = Nom.InnerText;
objFitxer.Hash = Hash.InnerText;
objFitxer.DataCreacio = DateTime.ParseExact(DataCreacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.DataVerificacio = DateTime.ParseExact(DataVerificacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.Estat = Estat.InnerText;
objFitxer.MidaEnBytes = long.Parse(MidaEnBytes.InnerText);
DicFitxers.Add(objFitxer.Nom, objFitxer);
}
return DicFitxers;
}
publicstaticvoid crea(string pPath)
{
bool Procesa_carpeta = false;
if (File.Exists(pPath + "\\hasher.xml"))
{
if (Creacio_de_cero)
{
File.Delete(pPath + "\\hasher.xml");
Console.WriteLine(ObtenirData() + " - Carpeta " + pPath + " amb fitxer de hashos, esborrat.");
Procesa_carpeta = true;
}
else
{
Console.WriteLine(ObtenirData() + " - Carpeta " + pPath + " amb fitxer de hashos, no procesada.");
Procesa_carpeta = false;
}
}
if (Procesa_carpeta)
{
Console.WriteLine(ObtenirData() + " - creant fitxer hashos: " + pPath);
DirectoryInfo dir = newDirectoryInfo(pPath);
FileInfo[] files = dir.GetFiles();
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = newDictionary<string, clsFitxer>();
foreach (FileInfo Fitxer in files)
{
try
{
if (Fitxer.Name.ToLower() != "hasher.exe" && Fitxer.Name.ToLower() != "hasher.xml")
{
string hashValueStr = SHA256HashFile(Fitxer.FullName);
Console.WriteLine(ObtenirData() + " - hashejat: " + Fitxer.Name);
objFitxer = new clsFitxer(Fitxer.Name,
DateTime.Now,
DateTime.Now,
Fitxer.Length,
hashValueStr,
"CREAT");
DicFitxers.Add(Fitxer.Name, objFitxer);
}
}
catch (IOException e)
{
Console.WriteLine("I/O Exception: " + e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("Access Exception: " + e.Message);
}
}
Save(pPath, DicFitxers);
}
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
crea(Carpeta);
}
}
}
publicstaticvoid Save(string pPath, Dictionary<string, clsFitxer> DicFitxers)
{
XmlDocument Doc = newXmlDocument();
XmlNode Fitxers;
XmlNode Fitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
Doc.LoadXml("<?xml version=\ "1.0\ " standalone=\ "yes\ "?><fitxers></fitxers>");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
Fitxer = Doc.CreateNode(XmlNodeType.Element, "fitxer", "");
Nom = Doc.CreateNode(XmlNodeType.Element, "nom", "");
Hash = Doc.CreateNode(XmlNodeType.Element, "hash", "");
DataCreacio = Doc.CreateNode(XmlNodeType.Element, "datacreacio", "");
DataVerificacio = Doc.CreateNode(XmlNodeType.Element, "dataverificacio", "");
Estat = Doc.CreateNode(XmlNodeType.Element, "estat", "");
MidaEnBytes = Doc.CreateNode(XmlNodeType.Element, "midaenbytes", "");
Nom.InnerText = objFitxer.Value.Nom;
Hash.InnerText = objFitxer.Value.Hash;
DataCreacio.InnerText = ObtenirData(objFitxer.Value.DataCreacio);
DataVerificacio.InnerText = ObtenirData(objFitxer.Value.DataVerificacio);
Estat.InnerText = objFitxer.Value.Estat;
MidaEnBytes.InnerText = objFitxer.Value.MidaEnBytes.ToString();
Fitxer.AppendChild(Nom);
Fitxer.AppendChild(Hash);
Fitxer.AppendChild(DataCreacio);
Fitxer.AppendChild(DataVerificacio);
Fitxer.AppendChild(Estat);
Fitxer.AppendChild(MidaEnBytes);
Fitxers.AppendChild(Fitxer);
}
Doc.Save(pPath + "\\hasher.xml");
}
}
}
Ara la clase:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hasher
{
class clsFitxer
{
publicstring Nom { get; set; }
publicDateTime DataCreacio { get; set; }
publicDateTime DataVerificacio { get; set; }
publiclong MidaEnBytes { get; set; }
publicstring Hash { get; set; }
publicstring Estat { get; set; }
public clsFitxer()
{
}
public clsFitxer(string pNom,
DateTime pDataCreacio,
DateTime pDataVerificacio,
long pMidaEnBytes,
string pHash,
string pEstat)
{
Nom = pNom;
DataCreacio = pDataCreacio;
DataVerificacio = pDataVerificacio;
MidaEnBytes = pMidaEnBytes;
Hash = pHash;
Estat = pEstat;
}
}
}
#29/07/2019 09:28 Programació C# Autor: Alex Canalda
Quan s'estableix una comunicació amb un servidor es pot fer xifrada. Actualment gairebé totes les connexions són xifrades, es coneix com SSL. En una connexió SSL normalment s'identifica el servidor, el client que es connecta no. Però els servidors poden anar un pas més enllà i demanar al client que s'identifiqui. Això es coneix amb varis noms, 2-way SSL, 2WSSL o Mutual authentication.
Quan es programa s'ha de tenir en compte que calen uns passos extra per configurar la connexió. Cal afegir un certificat que identifiqui al client i que alguna CA (certificate authority) del servidor validi (reconegui). El curiós és que el certificat acostuma a estar guardat en un fitxer P12, però un contenidor P12 pot tenir més d'un al seu interior. No he trobat en la llibreria C# d'accés al P12 cap forma d'accedir posant el nom del certificat. Així que millor posar un P12 que contingui un únic certificat. Les variables CertStorageP12, PwdCertStorage són la ruta d'accés al fitxer (el path amb el nom del fitxer) i la contrasenya.
Estava mirant funcions en Javascript per fer "coses", anava revisant el W3Schools i he trobat una funció que m'ha cridat l'atenció per enrevessada, no és que ho sigui gaire, però no costava escriure-la bé, d'una forma més clara.
I ja se que d'opinions hi ha tan variades com els colors, però aquesta és la meva. Aquests dos codis fan exactament el mateix, és l'exemple d'una barra de progres :
function move() {
var elem = document.getElementById("myBar");
var width = 1;
var id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
}
}
}
I ara l'altra:
var id;
var width = 0;
var elem = document.getElementById("myBar");
function move() {
id = setInterval(frame, 100);
}
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
}
}
Jo sincerament m'agrada veure que una variable és global, que es farà servir per conservar un valor entre crides a la mateixa rutina, que una rutina es cridarà varies vegades, que comença i acaba... Això del Javascript que defineixes funcions dins d'altres no m'acaba d'agradar.
#18/06/2019 18:11 Programació Javascript Autor: Alex Canalda
Els programadors, en general, anem aprenent segons fem, a vegades per gust, a vegades per motius laborals. I m'he trobat una reflexió interessant sobre l'aprenentatge al blog d'Scott Hanselman que vaig seguint segons va publicant.
Ell explica que se li acosta un jove i li pregunta que ha d'estudiar, per que estava preocupat per la universitat que li ensenyen .NET i ara el que es porta és .NET Core. I ell li contesta:
For the young person I spoke to, yes .NET Core may be a little different from .NET Framework, and they might both be different from Ruby or JavaScript, but strings are strings, loops are loops, memory is memory, disk I/O is what it is, and we all share the same networks. Processes and threads, ports, TCP/IP, and DNS - understanding the basic building blocks are important.
Drive a Honda or a Jeep, you'll still need to replace your tires and think about the road you're driving on, on the way to the grocery store.
Jo sempre critico els programadors que no saben com funciona un disc, com va una cache, perque al fi i al cap el hardware és la carretera que ens porta. O per els que presumeixen de fer les coses en l'últim llenguatge de moda: recordo que un string és un string, un bucle un bucle i un if... Ademés sempre penso en el manteniment del software. Quantes explicacions ha de rebre un ésser humà per entendre el codi d'un programa? A vegades quan els compiladors incorporen millores, no són tan una millora com un inconvenient... veiem aquesta del C# 8.0, primer el codi clàssic:
Fa un temps vaig fer el hashejador, un software multifil que per cada disc dur calcula el hash dels fitxers que estan en un BBDD i compara el resultat amb el que ja té guardat. Serveix per protegir-se del bit rotting. El cert és que hem va força bé, quan tingui temps el milloraré per fer servir SHA256 enlloc de SHA1 però això serà una altra història. L'inconvenient que li veig al hashejador és que necessita una BBDD, una infraestructura, etc...
El PowerShell disposa d'una comanda Get-FileHash que calcula hashs de fitxers, però no els guarda enlloc, els treu per pantalla. Suposo que es podria escriure alguna utilitat que el guardi en un fitxer de text però aleshores també caldria escriure una altra "cosa" (referint-me al llenguatge del PowerShell) per tal que compari els hashs existents amb el que es calcula en aquell moment. Però jo no sóc de fer coses en PowerShell.
Per això ha sortit el petit hashejador, una utilitat per calcular els hash de fitxers i deixar el resultat en un fitxer XML dins la mateixa carpeta on estan els fitxers. Més endavant el petit hashejador pot fer el procés de verificació per veure que tot està a lloc. El problema que li veig és que permet detectar errors però no corregir-los, es a dir el petit hashejador et dirà que no li encaixa la verificació d'un fitxer però un cop detectat... que fas? Com el recuperes? Això ho fa el seu germà gran que verifica un fitxer en diferents discs durs i llavors saps quina còpia és la bona. Però de moment, el petit hashejador només fa això, detectar sense corregir.
El petit hashejador és una aplicació de línia de comandes (o "aplicación de consola") formada per un programa principal i una classe. El programa principal té la funció de verificar i la de crear el fitxeret amb els hashos, la de guardar i llegir el fitxer XML. No és que sigui gaire complicat. Primer el programa principal:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace Hasher
{
classProgram
{
privatestaticstring ExecutablePath = "";
privatestaticstring CarpetaAProcessar = "";
privatestaticbool Recursiu = false;
staticvoid Main(string[] args)
{
string AppPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
ExecutablePath = Path.GetDirectoryName(AppPath);
try
{
if (args.Length > 0)
{
string Accio = args[0].ToLower();
if (args.Length > 1)
{
if (args[1] != null)
{
CarpetaAProcessar = args[1];
}
}
if (args.Length > 2)
{
if (args[2] != null)
{
if (args[2].ToLower() == "-r")
{
Recursiu = true;
}
}
}
if (CarpetaAProcessar != "")
{
if (!Directory.Exists(CarpetaAProcessar))
{
Console.WriteLine("Carpeta no trobada: " + CarpetaAProcessar);
return;
}
}
else
{
Console.WriteLine("Carpeta a processar no informada");
return;
}
switch (Accio)
{
case"crea":
crea(CarpetaAProcessar);
break;
case"verifica":
if (!File.Exists(CarpetaAProcessar + "\\hasher.xml"))
{
Console.WriteLine("No hi ha fitxer de hashos.");
return;
}
verifica(CarpetaAProcessar);
break;
default:
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r]\" crea un fitxer XML amb els Hash dels fitxers, -r indica recursiu");
Console.WriteLine("\"verifica path [-r]\" verifica que els fitxers tinguin el Hash -r indica recursiu");
break;
}
}
else
{
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r]\" crea un fitxer XML amb els Hash dels fitxers -r indica recursiu");
Console.WriteLine("\"verifica path [-r]\" verifica que els fitxers tinguin el Hash -r indica recursiu");
}
}
catch(Exception Err)
{
Console.WriteLine(Err.Message);
}
}
publicstaticstring ObtenirData(DateTime data)
{
return data.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
publicstaticstring ObtenirData()
{
returnDateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
publicstaticvoid verifica(string pPath)
{
Console.WriteLine(ObtenirData() + " - verificant carpeta: " + pPath);
SHA256 mySHA256 = SHA256.Create();
Dictionary<string, clsFitxer> DicFitxers;
DicFitxers = CarregaHashos(pPath);
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
try
{
if (File.Exists(pPath + "\\ " + objFitxer.Value.Nom))
{
FileInfo fiFitxer = newFileInfo(pPath + "\\ " + objFitxer.Value.Nom);
if (fiFitxer.Length != objFitxer.Value.MidaEnBytes)
{
Console.WriteLine("Fitxer amb mida diferent: " + fiFitxer.Name);
objFitxer.Value.Estat = "MIDA DIFERENT, actual: " + fiFitxer.Length;
}
else
{
FileStream fileStream = fiFitxer.Open(FileMode.Open, FileAccess.Read, FileShare.None);
// Be sure it's positioned to the beginning of the stream.
fileStream.Position = 0;
// Compute the hash of the fileStream.byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
// Close the file.
fileStream.Close();
if (hashValueStr == objFitxer.Value.Hash)
{
objFitxer.Value.Estat = "VERIFICAT";
}
else
{
Console.WriteLine("Fitxer amb hash canviat: " + fiFitxer.Name);
objFitxer.Value.Estat = "NO COINCIDEIX";
}
}
}
else
{
objFitxer.Value.Estat = "ESBORRAT";
}
objFitxer.Value.DataVerificacio = DateTime.Now;
}
catch (IOException e)
{
Console.WriteLine($"I/O Exception: {e.Message}");
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"Access Exception: {e.Message}");
}
}
Save(pPath, DicFitxers);
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach(string Carpeta in Carpetes)
{
verifica(Carpeta);
}
}
}
publicstaticDictionary<string, clsFitxer> CarregaHashos(string pPath)
{
XmlDocument Doc = newXmlDocument();
XmlNode Fitxers;
XmlNodeList llistaDeFitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = newDictionary<string, clsFitxer>();
Doc.Load(pPath + "\\hasher.xml");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
llistaDeFitxer = Fitxers.ChildNodes;
foreach (XmlNode Fitxer in llistaDeFitxer)
{
objFitxer = new clsFitxer();
Nom = Fitxer.SelectSingleNode("descendant::nom");
Hash = Fitxer.SelectSingleNode("descendant::hash");
DataCreacio = Fitxer.SelectSingleNode("descendant::datacreacio");
DataVerificacio = Fitxer.SelectSingleNode("descendant::dataverificacio");
Estat = Fitxer.SelectSingleNode("descendant::estat");
MidaEnBytes = Fitxer.SelectSingleNode("descendant::midaenbytes");
objFitxer.Nom = Nom.InnerText;
objFitxer.Hash = Hash.InnerText;
objFitxer.DataCreacio = DateTime.ParseExact(DataCreacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.DataVerificacio = DateTime.ParseExact(DataVerificacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.Estat = Estat.InnerText;
objFitxer.MidaEnBytes = long.Parse(MidaEnBytes.InnerText);
DicFitxers.Add(objFitxer.Nom, objFitxer);
}
return DicFitxers;
}
publicstaticvoid crea(string pPath)
{
Console.WriteLine(ObtenirData() + " - creant fitxer hashos: " + pPath);
if (File.Exists(pPath + "\\hasher.xml"))
{
File.Delete(pPath + "\\hasher.xml");
}
SHA256 mySHA256 = SHA256.Create();
DirectoryInfo dir = newDirectoryInfo(pPath);
FileInfo[] files = dir.GetFiles();
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = newDictionary<string, clsFitxer>();
foreach (FileInfo Fitxer in files)
{
try
{
if (Fitxer.Name.ToLower() != "hasher.exe" && Fitxer.Name.ToLower() != "hasher.xml")
{
FileStream fileStream = Fitxer.Open(FileMode.Open);
// Be sure it's positioned to the beginning of the stream.
fileStream.Position = 0;
// Compute the hash of the fileStream.byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
// Close the file.
fileStream.Close();
objFitxer = new clsFitxer(Fitxer.Name, DateTime.Now, DateTime.Now, Fitxer.Length, hashValueStr, "CREAT");
DicFitxers.Add(Fitxer.Name, objFitxer);
}
}
catch (IOException e)
{
Console.WriteLine($"I/O Exception: {e.Message}");
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"Access Exception: {e.Message}");
}
}
Save(pPath, DicFitxers);
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
crea(Carpeta);
}
}
}
publicstaticvoid Save(string pPath, Dictionary<string, clsFitxer> DicFitxers)
{
XmlDocument Doc = newXmlDocument();
XmlNode Fitxers;
XmlNode Fitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
Doc.LoadXml("<?xml version=\"1.0\" standalone=\"yes\"?><fitxers></fitxers>");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
Fitxer = Doc.CreateNode(XmlNodeType.Element, "fitxer", "");
Nom = Doc.CreateNode(XmlNodeType.Element, "nom", "");
Hash = Doc.CreateNode(XmlNodeType.Element, "hash", "");
DataCreacio = Doc.CreateNode(XmlNodeType.Element, "datacreacio", "");
DataVerificacio = Doc.CreateNode(XmlNodeType.Element, "dataverificacio", "");
Estat = Doc.CreateNode(XmlNodeType.Element, "estat", "");
MidaEnBytes = Doc.CreateNode(XmlNodeType.Element, "midaenbytes", "");
Nom.InnerText = objFitxer.Value.Nom;
Hash.InnerText = objFitxer.Value.Hash;
DataCreacio.InnerText = ObtenirData(objFitxer.Value.DataCreacio);
DataVerificacio.InnerText = ObtenirData(objFitxer.Value.DataVerificacio);
Estat.InnerText = objFitxer.Value.Estat;
MidaEnBytes.InnerText = objFitxer.Value.MidaEnBytes.ToString();
Fitxer.AppendChild(Nom);
Fitxer.AppendChild(Hash);
Fitxer.AppendChild(DataCreacio);
Fitxer.AppendChild(DataVerificacio);
Fitxer.AppendChild(Estat);
Fitxer.AppendChild(MidaEnBytes);
Fitxers.AppendChild(Fitxer);
}
Doc.Save(pPath + "\\hasher.xml");
}
publicstaticstring ConvertByteArrayToHexString(byte[] ba)
{
StringBuilder sb = newStringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString().ToUpper();
}
}
}
Després la classe:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hasher
{
class clsFitxer
{
publicstring Nom { get; set; }
publicDateTime DataCreacio { get; set; }
publicDateTime DataVerificacio { get; set; }
publiclong MidaEnBytes { get; set; }
publicstring Hash { get; set; }
publicstring Estat { get; set; }
public clsFitxer()
{
}
public clsFitxer(string pNom, DateTime pDataCreacio, DateTime pDataVerificacio, long pMidaEnBytes, string pHash, string pEstat)
{
Nom = pNom;
DataCreacio = pDataCreacio;
DataVerificacio = pDataVerificacio;
MidaEnBytes = pMidaEnBytes;
Hash = pHash;
Estat = pEstat;
}
}
}
I fet!
#29/04/2019 17:36 Programació C# Autor: Alex Canalda
A vegades veig llenguatges de programació que penso... "quina llumenera haurà fet això?".
Són llenguatges on va tot empotrat, com el Razor. Són llenguatges on es barreja tot, l'HTML amb lògica, amb dades... Entenc que en el món ha d'haver-hi de tot i al gust de tothom. Així que la mateixa empresa (en aquest cas MS) desenvolupa molts llenguatges per cobrir els gustos de tots. Articles com aquest em fan sagnar els ulls...
Aquí va tot barrejat..., els events? Cap dins. L'estil? Cap dins. Les dades? Cap dins...
Penso que en un equip de programadors hi ha gent que en sap més, gent que menys, i ara que hem toca repartir tasques entre persones ja se de quin peu calça cadascú. Aleshores quan tinc que passar-lis feina, al que sap HTML li passo HTML, el que li va el Javascript li passo Javascript, el de codi servidor, el de SQLs... Així ells (els programadors) estan contents, triguen menys i el resultat és de millor qualitat. Tampoc obligo a saber de tot i es poden especialitzar. Si saps de tot al final no saps el detall que fa que no funcioni el que fas, i perds temps buscant-lo.
Així doncs penso que millor cada element separat, HTML, CSS, dades, enviament/recepció de dades del servidor. De fet tal com treballo puc canviar un servidor web per un altra d'una tecnologia diferent si compleixo una "API" o un cert format JSON acordat entre la part que està al navegador i la part servidora, sense tocar ni un punt d'aquesta. Llavors no entenc per que ho volen tot barrejat. Potser per prototipus o temes molt ràpids... si no, no veig la raó de l'existència dels llenguatges barrejats. Jo prefereixo els poders separats...
#02/08/2018 14:15 Programació C# Javascript Autor: Alex Canalda
Hi ha coses que un website no vol que el IIS serveixi cap als clients via HTTP. Però a nivell de programació es vol que els ASPX, ASHX del servidor sí accedeixin. Aleshores una forma fàcil de fer-ho és aquesta. S'exclou una carpeta i a dins es posa el contingut que no es vol servir.
Segueixo pulint el tema del programa que controla el bit-rotting i la coherència de la còpia de seguretat. Tinc una tasca que triga força en executar-se i per no deixar l'interface d'usuari sense activitat (que et sorgeix el dubte... s'ha penjat o està fent algo?) aleshores millor mostrar un percentatge de progres.
El procés s'executa en un thread diferent del de l'interface d'usuari i consisteix en un bucle que executa consultes contra la BBDD. Es sap quantes consultes cal fer i dins del bucle que les fa es sap quantes en portes. Aleshores hi ha l'opció de calcular el percentatge a cada volta de bucle, però això és fer el càlcul massa sovint, també vaig fer l'opció de calcular cada "n" voltes de bucle però això depèn de si hi ha moltes consultes o poques. Aquestes dues opcions no em van agradar, jo volia que cada cert temps em digui el progres i aleshores vaig pensar en un timer. Cada n segons, 5 per exemple, que em digui que tal va.
I clar, com es posa un timer en un thread en C#? El cert és que m'ha resultat més fàcil del que hem pensava. Això de programar per que et ve degust està molt bé, perquè fas el que vols amb el temps que vols, es a dir fins que et canses. Podria haver estat un problema més difícil i tindria que haver dedicat més temps, però no, fàcil, fàcil. D'aquí poc com l'Arguiñano, rico, rico :D
Cal posar el using dels Timers, les variables globals que gestionen el càlcul del progres, la variable del Timer, inicialitzar-ho tot plegat, i fer la rutineta que fa el càlcul (UpdateProgress) i presto! Un Timer. No està de més, en catch de quan el Thread està sent abortat aturar el timer.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace Dir
{
class clsBuscaRepes
{
public frmInterface Interface = null;
publicdecimal TantPerCentProgress = 0;
privateint Progress = 0;
privateint Total = 0;
private System.Timers.Timer Tmr = new System.Timers.Timer();
publicvoid BuscaRepes()
{
try
{
clsConfig Config = new clsConfig();
string SQL = "";
DataTable TBLParaules, TBLDuplicats, TBLFitxer, TBLVerificats;
string CadConn = "";
bool UseBBDD = false;
bool Primer = true;
SqlConnection Conn = null;
string IdFitxerActual = "", IdFitxerAnterior = "";
int NumRepes = 0;
string HashActual = "";
string HashAnterior = "";
clsSQLServer SQLSvr = new clsSQLServer();
Tmr.Interval = 1000;
Tmr.Elapsed += new ElapsedEventHandler(UpdateProgress);
Config.Initialize();
UseBBDD = bool.Parse(Config.GetVal("UseBBDD"));
Interface.Log("Començant buscar fitxers repetits");
if (UseBBDD)
{
Conn = newSqlConnection();
CadConn = Config.GetVal("CadConn");
Conn.ConnectionString = CadConn;
Conn.Open();
Interface.Log("Conectat a BBDD: " + Conn.DataSource);
SQLSvr.CadConn = CadConn;
SQLSvr.Conn = Conn;
Progress = 0;
Total = 0;
SQL = "DELETE FROM ResultatsDuplicats";
SQLSvr.ExecNonQuery(SQL);
Interface.Log("Iniciant duplicats per hash");
SQL = "SELECT * FROM Fitxers WHERE Hash IN(SELECT Hash FROM fitxers "
SQL += "GROUP BY Hash HAVING ( COUNT(Hash) > 1 )) ORDER BY Hash";
TBLDuplicats = SQLSvr.Exec(SQL);
foreach (DataRow DR in TBLDuplicats.Rows)
{
HashActual = DR["Hash"].ToString();
if (HashActual == HashAnterior)
{
IdFitxerActual = DR["IdFitxer"].ToString();
SQL = "SELECT * FROM Verificats WHERE IdFitxer=" + IdFitxerAnterior + " ";
SQL += "AND IdFitxerVerificat=" + IdFitxerActual;
TBLVerificats = SQLSvr.Exec(SQL);
if (TBLVerificats.Rows.Count == 0)
{
SQL = "SELECT * FROM Fitxers WHERE IdFitxer=" + IdFitxerAnterior;
TBLFitxer = SQLSvr.Exec(SQL);
Interface.Log("Duplicat, fitxer actual: " + TBLFitxer.Rows[0]["IdFitxer"].ToString());
Interface.Log(", " + TBLFitxer.Rows[0]["Nom"].ToString());
Interface.Log("Duplicat: " + DR["IdFitxer"].ToString() + ", " + DR["Nom"].ToString());
Interface.Log("--------------------------------------------------");
SQL = "INSERT INTO ResultatsDuplicats (IdFitxer, IdFitxerPossibleDuplicat) "
SQL += "VALUES (" + IdFitxerAnterior + ", " + DR["IdFitxer"].ToString() + ");";
SQLSvr.ExecNonQuery(SQL);
NumRepes++;
}
}
else
{
HashAnterior = HashActual;
IdFitxerAnterior = DR["IdFitxer"].ToString();
}
}
SQL = "SELECT Paraula, IdFitxer FROM Paraules ORDER BY IdFitxer";
TBLParaules = SQLSvr.Exec(SQL);
SQL = "";
IdFitxerAnterior = "";
IdFitxerActual = "";
Total = TBLParaules.Rows.Count;
//Començar el timer
Tmr.Start();
foreach (DataRow Paraula in TBLParaules.Rows)
{
IdFitxerActual = Paraula["IdFitxer"].ToString();
if (IdFitxerActual == IdFitxerAnterior || Primer)
{
SQL += " AND Nom LIKE '%" + Paraula["Paraula"].ToString().Replace("'", "''") + "%'";
if (Primer)
{
Primer = false;
IdFitxerAnterior = IdFitxerActual;
}
}
else
{
SQL = "SELECT * FROM Fitxers WHERE IdCarpeta IN ";
SQL += "(SELECT IdCarpeta FROM Carpetes WHERE Duplicats=1) ";
SQL += "AND IdFitxer<>" + IdFitxerAnterior + " " + SQL;
TBLDuplicats = SQLSvr.Exec(SQL);
foreach (DataRow Duplicat in TBLDuplicats.Rows)
{
SQL = "SELECT * FROM Verificats ";
SQL += " WHERE IdFitxer=" + IdFitxerAnterior + " ";
SQL += "AND IdFitxerVerificat=" + Duplicat["IdFitxer"].ToString();
TBLVerificats = SQLSvr.Exec(SQL);
if (TBLVerificats.Rows.Count == 0)
{
SQL = "SELECT * FROM Fitxers WHERE IdFitxer=" + IdFitxerAnterior;
TBLFitxer = SQLSvr.Exec(SQL);
Interface.Log("Duplicat, fitxer actual: " + TBLFitxer.Rows[0]["IdFitxer"].ToString());
Interface.Log(", " + TBLFitxer.Rows[0]["Nom"].ToString());
Interface.Log("Duplicat: " + Duplicat["IdFitxer"].ToString() + ", " + Duplicat["Nom"].ToString());
Interface.Log("--------------------------------------------------");
SQL = "INSERT INTO ResultatsDuplicats (IdFitxer, IdFitxerPossibleDuplicat) "
SQL += " VALUES (" + IdFitxerAnterior + ", " + Duplicat["IdFitxer"].ToString() + ");";
SQLSvr.ExecNonQuery(SQL);
NumRepes++;
}
}
SQL = " AND Nom LIKE '%" + Paraula["Paraula"].ToString().Replace("'", "''") + "%'";
IdFitxerAnterior = IdFitxerActual;
}
Progress++;
}
}
Tmr.Stop();
Interface.Log("Total repetits: " + NumRepes);
Interface.BuscaRepesFinished();
}
catch (ThreadAbortException Ex)
{
if (Tmr.Enabled) Tmr.Stop();
}
catch(Exception Err)
{
Interface.Log("Error: " + Err.Message);
}
}
publicvoid UpdateProgress(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
TantPerCentProgress = (decimal)(Progress * 100) / (decimal)Total;
Interface.Log("Processades " + TantPerCentProgress.ToString("N2") + "% de paraules");
}
catch(Exception Err)
{
}
}
}
}
#13/03/2018 18:35 Programació C# Autor: Alex Canalda
Depenent del projecte on estem a vegades no cal muntar classes d'accés a dades, capes i capes de software inútil per executar una mera consulta. També cal valorar la mantenibilitat, allò de que les capes afavoreixen el manteniment, jo sempre he trobat que entorpeixen el manteniment... Però sí que crec necessari que les consultes, encara que siguin un string en el codi, siguin gestionades de forma centralitzada. És en aquest punt quan va sorgir la clsSQLServer. D'això ja fa 5 o més anys... però no se per que no l'he posat al blog fins ara. Bé de fet, l'he ampliat fa pocs dies, portava des del 2013 sense modificacions.
Aquesta classe com el seu nom indica gestiona les consultes al servidor de base de dades. De fet no se com Microsoft no l'han fet ells mateixos. Vull dir que com programador el que vull és executar una sentència SQL i tenir una taula de retorn, sense preocupar-me de si és un Adapter o un Command o X, però bé, ja que MS no s'inspira ho fet jo. Té uns quants mètodes principals i sobrecarregats:
Exec: Executa un consulta SQL i retorna una taula. Es pot escollir entre no preocupar-se per la connexió, o sí, o afegir-hi una transacció.
ExecInsertWithIdentity: Executa un INSERT contra una taula que tingui una clau primària (PK) de tipus identitat. I un cop fet l'INSERT retorna el valor de la PK que ha creat com un long.
ExecNonQuery: Serveix per executar consultes que no retornen res, tipus UPDATEs, DELETEs o INSERTs que no cal recuperar la PK. Retorna els registres afectats per la consulta.
ExecScalar: Serveix per executar consultes que retornen un valor sencer, com un màxim, un mínim, un COUNT etc... De moment no m'ha fet falta un altra tipus de dada en el retorn.
FDateSQL: Aquesta és una utilitat per treballar amb dates en SQL Server. Retorna la data en un string en format ISO 8601: yyyy-mm-ddThh:mi:ss. Aquest format el bo que té és que no depèn dels regional settings.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Configuration;
namespace Viewer
{
publicclass clsSQLServer
{
public clsSQLServer()
{
Conn = null;
}
publicSqlConnection Conn { get; set; }
privatestring _Ver = "07/03/2018";
publicstring Ver
{
get
{
return _Ver;
}
}
publicstring CadConn { get; set; }
publicstring FDateSQL(DateTime D)
{
//ISO 8601: yyyy-mm-ddThh:mi:ssreturn D.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss");
}
/// <summary>/// Executa una SQL que retorna resultats contra una conexió, no modifica l'estat de la conexió ni de la transaccio/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
DataTable TBL = newDataTable();
SqlCommand SqlComm = newSqlCommand();
SqlDataReader SqlReader;
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
SqlReader = SqlComm.ExecuteReader();
TBL.Load(SqlReader);
return TBL;
}
/// <summary>/// Executa una SQL que retorna resultats contra una conexió, no modifica l'estat de la conexió/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL, SqlConnection SqlConn)
{
return Exec(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que retorna resultats, si està informada la variable Conn la fa/// servir de conexio (ha d'estar oberta), si no crea una i la tanca/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL)
{
DataTable TBL;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
TBL = Exec(SQL, SqlConn);
if (Local) SqlConn.Close();
return TBL;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. Retorna la identitat creada. /// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL)
{
long Identity = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Identity = ExecInsertWithIdentity(SQL, SqlConn);
if (Local) SqlConn.Close();
return Identity;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. /// Retorna la identitat creada. No modifica l'estat de la connexió/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL, SqlConnection SqlConn)
{
long Identity = 0;
Identity = ExecInsertWithIdentity(SQL, SqlConn, null);
return Identity;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. Retorna la identitat creada/// </summary>/// <param name="SQL">Sentència INSERT SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
long Identity = 0;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
if (!SQL.EndsWith(";")) SQL += ";";
SQL += " SELECT SCOPE_IDENTITY();";
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
Identity = (long)(decimal)SqlComm.ExecuteScalar();
return Identity;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només els registres afectats. /// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecNonQuery(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL, SqlConnection SqlConn)
{
return ExecNonQuery(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que no retorna resultats/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
Results = SqlComm.ExecuteNonQuery();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecScalar(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL, SqlConnection SqlConn)
{
return ExecScalar(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
object objResult;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
objResult = SqlComm.ExecuteScalar();
if (objResult != null && objResult != DBNull.Value)
{
Results = int.Parse(objResult.ToString());
}
return Results;
}
}
}
#08/03/2018 12:46 Programació C# SQLServer Autor: Alex Canalda