Categories
Llibres Programació C# Javascript Hardware Fotografia Pelis Anglès Android Series Excursions Cites SQLServer Software HTML/CSS Politikon Estilogràfiques Tintes
Contacte: Àlex
|
Com treure atribut ReadOnly a fitxers |
He tingut que modificar els atributs de fitxers, concretament treure l'atribut de només lectura (ReadOnly). Es pot fer de dues maneres:
Old style, MS-DOS, o linia de comandes:
attrib -r /s
O amb el nou i poderós "Powershell":
$Path = "C:\Desenvolupament\*"
$Files = Get-ChildItem $Path -Recurse
ForEach ($File in $Files)
{
Write-Host "Arxiu: " $File " IsReadOnly: " $File.IsReadOnly
if ($File.Attributes -ne "Directory" -and $File.Attributes -ne "Directory, Archive")
{
if ($File.IsReadOnly -eq $true )
{
try
{
Set-ItemProperty -path $File.FullName -name IsReadOnly -value $false
write-host "Arxiu:" $File.FullName "ja no es readonly" -foregroundcolor "magenta"
}
catch [Exception]
{
Write-Host "Error a l arxiu " $Path "\" $File
Write-Host $_.Exception.Message
}
}
}
}
Crec que la forma antiga ja val... Això sí, la nova els pinta magenta, mmmm... :D | #25/10/2019 19:43 Programació Autor: Alex Canalda
|
El petit hashejador ha crescut |
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
{
class Program
{
private static string ExecutablePath = "";
private static string CarpetaAProcessar = "";
private static bool Recursiu = false;
private static bool Creacio_de_cero = false;
private static string Accio = "";
private static bool Continua = false;
static void 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);
}
}
private static void 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);
}
}
}
public static string 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;
}
private static void 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 = new Dictionary<string, clsFitxer>();
clsFitxer FitxerActualitzat = null;
DicFitxers = CarregaHashos(pPath);
DirectoryInfo dir = new DirectoryInfo(pPath);
FileInfo[] Fitxers = dir.GetFiles();
Console.WriteLine(ObtenirData() + " - Processant " + pPath);
foreach (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);
}
}
foreach (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);
}
}
}
private static void 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("\\\\ ", "\\ ");
}
}
}
private static void 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);
}
}
}
public static string ObtenirData(DateTime data)
{
return data.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static string ObtenirData()
{
return DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static void 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 = new FileInfo(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)
{
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);
}
}
}
public static Dictionary<string, clsFitxer> CarregaHashos(string pPath)
{
XmlDocument Doc = new XmlDocument();
XmlNode Fitxers;
XmlNodeList llistaDeFitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<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;
}
public static void 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 = new DirectoryInfo(pPath);
FileInfo[] files = dir.GetFiles();
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<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);
}
}
}
public static void Save(string pPath, Dictionary<string, clsFitxer> DicFitxers)
{
XmlDocument Doc = new XmlDocument();
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
{
public string Nom { get; set; }
public DateTime DataCreacio { get; set; }
public DateTime DataVerificacio { get; set; }
public long MidaEnBytes { get; set; }
public string Hash { get; set; }
public string 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
|
2WSSL (a.k.a Mutual authentication) en C# |
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.
HttpWebRequest req = WebRequest.CreateHttp(URL);
X509Certificate2 cert = null;
X509CertificateCollection certColl = null;
cert = new X509Certificate2(CertStorageP12, PwdCertStorage, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
certColl = new X509CertificateCollection();
certColl.Add(cert);
req.ClientCertificates = certColl;
req.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequired;
| #19/07/2019 14:26 Programació C# Autor: Alex Canalda
|
Funcions en Javascript |
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
|
Que aprendre |
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:
switch (policy)
{
case FileExistsPolicy.Fail:
throw new Exception($"File '{targetFile}' already exists.");
case FileExistsPolicy.Skip:
return false;
case FileExistsPolicy.Overwrite:
return true;
case FileExistsPolicy.OverwriteIfNewer:
return File.GetLastWriteTimeUtc(targetFile) < File.GetLastWriteTimeUtc(sourceFile);
default:
throw new ArgumentOutOfRangeException(nameof(policy), policy, message: null);
}
I la nova:
return policy switch
{
FileExistsPolicy.Fail => throw new Exception($"File '{targetFile}' already exists."),
FileExistsPolicy.Skip => false,
FileExistsPolicy.Overwrite => true,
FileExistsPolicy.OverwriteIfNewer => File.GetLastWriteTimeUtc(targetFile) < File.GetLastWriteTimeUtc(sourceFile),
// _ => throw new ArgumentOutOfRangeException(nameof(policy), policy, message: null)
};
Tampoc li veig la millora, canvien el ":" per "=>", ja posats podrien posar "-->", en fi, per gustos els colors. | #15/05/2019 12:05 Programació Autor: Alex Canalda
|
El petit hashejador |
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
{
class Program
{
private static string ExecutablePath = "";
private static string CarpetaAProcessar = "";
private static bool Recursiu = false;
static void 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);
}
}
public static string ObtenirData(DateTime data)
{
return data.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static string ObtenirData()
{
return DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static void 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 = new FileInfo(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);
fileStream.Position = 0;
byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
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);
}
}
}
public static Dictionary<string, clsFitxer> CarregaHashos(string pPath)
{
XmlDocument Doc = new XmlDocument();
XmlNode Fitxers;
XmlNodeList llistaDeFitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<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;
}
public static void 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 = new DirectoryInfo(pPath);
FileInfo[] files = dir.GetFiles();
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<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);
fileStream.Position = 0;
byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
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);
}
}
}
public static void Save(string pPath, Dictionary<string, clsFitxer> DicFitxers)
{
XmlDocument Doc = new XmlDocument();
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");
}
public static string ConvertByteArrayToHexString(byte[] ba)
{
StringBuilder sb = new StringBuilder(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
{
public string Nom { get; set; }
public DateTime DataCreacio { get; set; }
public DateTime DataVerificacio { get; set; }
public long MidaEnBytes { get; set; }
public string Hash { get; set; }
public string 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
|
Separació de poders... |
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
|
Excloent carpetes del IIS |
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.
<configuration>
<system.webServer>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="My_Directory" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
Fàcil, fàcil. | #18/04/2018 16:03 Programació Autor: Alex Canalda
|
Timers en C# |
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;
public decimal TantPerCentProgress = 0;
private int Progress = 0;
private int Total = 0;
private System.Timers.Timer Tmr = new System.Timers.Timer();
public void 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 = new SqlConnection();
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;
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);
}
}
public void 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
|
Executant consultes contra un SQL Server des de C# |
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
{
public class clsSQLServer
{
public clsSQLServer()
{
Conn = null;
}
public SqlConnection Conn { get; set; }
private string _Ver = "07/03/2018";
public string Ver
{
get
{
return _Ver;
}
}
public string CadConn { get; set; }
public string FDateSQL(DateTime D)
{
return D.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss");
}
public DataTable Exec(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
DataTable TBL = new DataTable();
SqlCommand SqlComm = new SqlCommand();
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;
}
public DataTable Exec(string SQL, SqlConnection SqlConn)
{
return Exec(SQL, SqlConn, null);
}
public DataTable Exec(string SQL)
{
DataTable TBL;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = new SqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
TBL = Exec(SQL, SqlConn);
if (Local) SqlConn.Close();
return TBL;
}
public long ExecInsertWithIdentity(string SQL)
{
long Identity = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = new SqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Identity = ExecInsertWithIdentity(SQL, SqlConn);
if (Local) SqlConn.Close();
return Identity;
}
public long ExecInsertWithIdentity(string SQL, SqlConnection SqlConn)
{
long Identity = 0;
Identity = ExecInsertWithIdentity(SQL, SqlConn, null);
return Identity;
}
public long ExecInsertWithIdentity(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
long Identity = 0;
SqlCommand SqlComm = new SqlCommand();
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;
}
public int ExecNonQuery(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = new SqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecNonQuery(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
public int ExecNonQuery(string SQL, SqlConnection SqlConn)
{
return ExecNonQuery(SQL, SqlConn, null);
}
public int ExecNonQuery(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
SqlCommand SqlComm = new SqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
Results = SqlComm.ExecuteNonQuery();
return Results;
}
public int ExecScalar(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = new SqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecScalar(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
public int ExecScalar(string SQL, SqlConnection SqlConn)
{
return ExecScalar(SQL, SqlConn, null);
}
public int ExecScalar(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
object objResult;
SqlCommand SqlComm = new SqlCommand();
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
|
<< Posts anteriors | Posts més recents >> |
|