PCB MS SQL 標量函式與表值函式(CLR) 實現檔案與目錄操作 PCB 工程系統 模擬windows域帳號登入
阿新 • • 發佈:2018-12-20
一.C#寫SQL SERVER(CLR)實現檔案操作
標量函式: 檔案移動 ,複製,檢測檔案存在,寫入新檔案文字,讀取文字,建立目錄,刪除目錄,檢測目錄是否存在
/// <summary> /// 將現有檔案複製到新檔案。允許覆蓋同名的檔案。 /// </summary> /// <param name="sourceFileName">要複製的檔案</param> /// <param name="destFileName">View Code目標檔案的名稱。不能是目錄。</param> /// <param name="overwrite">如果可以覆蓋目標檔案,則為 true;否則為 false。</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean FileCopy (string sourceFileName, string destFileName, bool overwrite) {try { File.Copy (sourceFileName, destFileName, overwrite); return File.Exists (destFileName); } catch (Exception) { return false; } return false; } /// <summary> /// 將指定檔案移到新位置,並提供指定新檔名的選項。/// </summary> /// <param name="sourceFileName">要複製的檔案</param> /// <param name="destFileName">目標檔案的名稱。不能是目錄。</param> /// <param name="overwrite">如果可以覆蓋目標檔案,則為 true;否則為 false。</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean FileMove (string sourceFileName, string destFileName, bool overwrite) { try { bool isExists = File.Exists (destFileName); if (isExists && overwrite) File.Delete (destFileName); if (isExists && !overwrite) return false; File.Move (sourceFileName, destFileName); return File.Exists (destFileName); } catch (Exception) { return false; } return false; } /// <summary> /// 確定指定的檔案是否存在。 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean FileExists (string FilePath) { try { return File.Exists (FilePath); } catch (Exception) { return false; } return false; } /// <summary> /// 建立一個新檔案,在其中寫入指定的字串,然後關閉檔案。如果目標檔案已存在,則覆蓋該檔案。 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static bool FileWriteText (string FilePath, string Contents) { try { File.WriteAllText (FilePath, Contents); return File.Exists (FilePath); } catch (Exception) { return false; } return false; } /// <summary> /// 讀取文字 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static string FileReadText (string FilePath) { try { return File.ReadAllText (FilePath); } catch (Exception) { return ""; } return ""; } /// <summary> /// 建立目錄 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static bool DirectoryCreateDirectory (string DirPath) { try { Directory.CreateDirectory (DirPath); return Directory.Exists (DirPath); } catch (Exception) { return false; } return false; } /// <summary> /// 刪除目錄 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <param name="recursive">是否刪除所有子目錄與檔案</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static bool DirectoryDelete (string DirPath, bool recursive) { try { Directory.Delete (DirPath, recursive); return !Directory.Exists (DirPath); } catch (Exception) { return false; } return false; } /// <summary> /// 目錄是否存在 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static bool DirectoryExists (string DirPath) { try { return Directory.Exists (DirPath); } catch (Exception) { return false; } return false; }
表值函式:讀取文字,獲取檔案資訊,獲取子目錄清單
/// <summary> /// 表值函式 ///--屬性 --說明 ///--DataAccess --指示該函式是否涉及訪問儲存在SQL Server的資料 ///--FillRowMethodName --在同一個類的方法的名稱作為表值函式(TVF),這個引數在表值函式中才會用到,用於指定表值函式的資料填充方法 ///--IsDeterministic --指示使用者定義的函式是否是確定性的 ///--IsPrecise --指示函式是否涉及不精確計算,如浮點運算 ///--Name --函式在SQL Server中註冊時使用的函式的名稱 ///--SystemDataAccess --指示該函式是否需要訪問儲存在系統目錄或SQL Server虛擬系統表中的資料 ///--TableDefinition --如果方法作為表值函式(TVF),則為一個字串,該字串表示表結構的定義 /// </summary> public partial class SQLfunction { /// <summary> /// SQL Server 讀取文字轉為表 /// </summary> /// <param name="separator"></param> /// <param name="pendingString"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction( DataAccess = DataAccessKind.Read, IsDeterministic = true, Name = "FileReadText2Table", FillRowMethodName = "SqlSplit_FillRow", TableDefinition = "SerialNumber int,StringValue nvarchar(1024)")] public static IEnumerable FileReadText2Table(string path) { string[] strs = { }; strs = File.ReadAllLines(path); List<ResultData> resultDataList = new List<ResultData>(); for (int i = 0; i < strs.Length; i++) { resultDataList.Add(new ResultData(i + 1, strs[i])); } return resultDataList; } /// <summary> /// SQL Server 檔案資訊獲取 /// </summary> /// <param name="path"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction( DataAccess = DataAccessKind.Read, IsDeterministic = true, Name = "FileInfo2Table", FillRowMethodName = "SqlKeyValue_FillRow", TableDefinition = "SerialNumber int,StringKey nvarchar(1024),StringValue nvarchar(1024)")] public static IEnumerable FileInfo2Table(string path) { List<ResultKeyValueData> resultDataList = new List<ResultKeyValueData>(); FileInfo fileInfo = new FileInfo(path); resultDataList.Add(new ResultKeyValueData(1, "FullName", fileInfo.FullName)); resultDataList.Add(new ResultKeyValueData(2, "DirectoryName", fileInfo.DirectoryName)); resultDataList.Add(new ResultKeyValueData(3, "Name", Path.GetFileNameWithoutExtension(fileInfo.FullName))); resultDataList.Add(new ResultKeyValueData(4, "Extension", fileInfo.Extension)); resultDataList.Add(new ResultKeyValueData(5, "IsReadOnly", fileInfo.IsReadOnly.ToString())); resultDataList.Add(new ResultKeyValueData(6, "CreationTime", fileInfo.CreationTime.ToString())); resultDataList.Add(new ResultKeyValueData(7, "LastAccessTime", fileInfo.LastAccessTime.ToString())); resultDataList.Add(new ResultKeyValueData(8, "LastWriteTime", fileInfo.LastWriteTime.ToString())); resultDataList.Add(new ResultKeyValueData(9, "Length", fileInfo.Length.ToString())); resultDataList.Add(new ResultKeyValueData(10, "Attributes", fileInfo.Attributes.ToString())); return resultDataList; } /// <summary> /// SQL Server 獲取目錄--子目錄清單 /// </summary> /// <param name="path"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction( DataAccess = DataAccessKind.Read, IsDeterministic = true, Name = "DirectoryGetFiles", FillRowMethodName = "SqlSplit_FillRow", TableDefinition = "SerialNumber int,StringValue nvarchar(1024)")] public static IEnumerable DirectoryGetFiles(string path) { string[] strs = { }; strs = Directory.GetFiles(path); List<ResultData> resultDataList = new List<ResultData>(); for (int i = 0; i < strs.Length; i++) { resultDataList.Add(new ResultData(i + 1, strs[i])); } return resultDataList; } /// <summary> /// SQL Server 獲取目錄--檔案清單 /// </summary> /// <param name="path"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction( DataAccess = DataAccessKind.Read, IsDeterministic = true, Name = "DirectoryGetDirectories", FillRowMethodName = "SqlSplit_FillRow", TableDefinition = "SerialNumber int,StringValue nvarchar(1024)")] public static IEnumerable DirectoryGetDirectories(string path) { string[] strs = { }; IntPtr admin_token = IntPtr.Zero; if (WinLogonHelper.LogonUser(ref admin_token) != 0) { using (WindowsIdentity wid_admin = new WindowsIdentity(admin_token)) { using (WindowsImpersonationContext wic = wid_admin.Impersonate()) { strs = Directory.GetDirectories(path); } } } List<ResultData> resultDataList = new List<ResultData>(); for (int i = 0; i < strs.Length; i++) { resultDataList.Add(new ResultData(i + 1, strs[i])); } return resultDataList; } } /// <summary> /// 表值函式 ///--屬性 --說明 ///--DataAccess --指示該函式是否涉及訪問儲存在SQL Server的資料 ///--FillRowMethodName --在同一個類的方法的名稱作為表值函式(TVF),這個引數在表值函式中才會用到,用於指定表值函式的資料填充方法 ///--IsDeterministic --指示使用者定義的函式是否是確定性的 ///--IsPrecise --指示函式是否涉及不精確計算,如浮點運算 ///--Name --函式在SQL Server中註冊時使用的函式的名稱 ///--SystemDataAccess --指示該函式是否需要訪問儲存在系統目錄或SQL Server虛擬系統表中的資料 ///--TableDefinition --如果方法作為表值函式(TVF),則為一個字串,該字串表示表結構的定義 /// </summary> public partial class SQLfunction { /// <summary> /// SQL Server 字串分割方法 /// </summary> /// <param name="separator"></param> /// <param name="pendingString"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction( DataAccess = DataAccessKind.Read, IsDeterministic = true, Name = "SqlSplit", FillRowMethodName = "SqlSplit_FillRow", TableDefinition = "SerialNumber int,StringValue nvarchar(1024)")] public static IEnumerable SqlSplit(SqlString separator, SqlString pendingString) { string _separator = string.Empty; string _pendingString = string.Empty; if (pendingString.IsNull) return null; _pendingString = pendingString.ToString(); if (string.IsNullOrEmpty(_pendingString)) return null; _separator = separator.IsNull ? "," : separator.ToString(); _separator = string.IsNullOrEmpty(_separator) ? "," : _separator; string[] strs = _pendingString.Split(new string[] { _separator }, StringSplitOptions.RemoveEmptyEntries); List<ResultData> resultDataList = new List<ResultData>(); for (int i = 0; i < strs.Length; i++) { resultDataList.Add(new ResultData(i + 1, strs[i])); } return resultDataList; } #region 表值變數 Id,Value /// <summary> /// 填充資料方法 /// </summary> /// <param name="obj"></param> /// <param name="serialNumber"></param> /// <param name="stringValue"></param> public static void SqlSplit_FillRow(Object obj, out SqlInt32 SerialNumber, out SqlString StringValue) { ResultData resultData = (ResultData)obj; SerialNumber = resultData.SerialNumber; StringValue = resultData.StringValue; } /// <summary> /// 定義返回型別 /// </summary> public class ResultData { /// <summary> /// 序號,即行號 /// </summary> public SqlInt32 SerialNumber { get; set; } /// <summary> /// 分割後的每個子字串 /// </summary> public SqlString StringValue { get; set; } public ResultData(SqlInt32 serialNumber, SqlString stringValue) { SerialNumber = serialNumber; StringValue = stringValue; } } #endregion #region 表值變數 ID,Key,Value /// <summary> /// 填充資料方法 /// </summary> /// <param name="obj"></param> /// <param name="serialNumber"></param> /// <param name="stringValue"></param> public static void SqlKeyValue_FillRow(Object obj, out SqlInt32 SerialNumber, out SqlString StringKey, out SqlString StringValue) { ResultKeyValueData resultData = (ResultKeyValueData)obj; SerialNumber = resultData.SerialNumber; StringKey = resultData.StringKey; StringValue = resultData.StringValue; } /// <summary> /// 定義返回型別 /// </summary> public class ResultKeyValueData { /// <summary> /// 序號,即行號 /// </summary> public SqlInt32 SerialNumber { get; set; } /// <summary> /// 鍵 /// </summary> public SqlString StringKey { get; set; } /// <summary> /// 值 /// </summary> public SqlString StringValue { get; set; } public ResultKeyValueData(SqlInt32 serialNumber, SqlString stringKey, SqlString stringValue) { SerialNumber = serialNumber; StringKey = stringKey; StringValue = stringValue; } } #endregion }View Code
二.SQL伺服器CLR配置(允許SQL呼叫.net程式)
sp_configure 'show advanced options', 1; RECONFIGURE WITH override GO sp_configure 'clr enabled', 1; RECONFIGURE WITH override GO Sp_changedbowner 'sa',true --sa改為當前登入使用者名稱 alter database [dbname] set trustworthy on --bbname 改為自己的庫名
三.註冊 CLR 程式集
create ASSEMBLY SQLfunctionAssembly FROM 'D:\SQLClr.dll' --改為自己C#寫的dll路徑填寫 WITH PERMISSION_SET = UNSAFE;
建立的.net程式集資料會寫入下表:
select * from sys.assemblies select * from sys.assembly_files
四.建立標量函式與表值函式(分別2類函式舉例)
1.標量函式----檔案複製
CREATE FUNCTION [dbo].[FileCopy](@sourceFileName [nvarchar](max), @destFileName [nvarchar](max), @overwrite [bit]) RETURNS [bit] WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLfunctionAssembly].[SQLClr.SQLfunction].[FileCopy]
2.表值函式----獲取檔案資訊
CREATE FUNCTION [dbo].[FileInfo2Table](@path [nvarchar](max)) RETURNS TABLE ( [SerialNumber] [int] NULL, [StringKey] [nvarchar](max) NULL, [StringValue] [nvarchar](max) NULL ) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLfunctionAssembly].[SQLClr.SQLfunction].[FileInfo2Table]
五.測試檔案操作函式
測試3個函式
說明一下:D:\features檔案是指伺服器上的D盤features檔案,而不是客戶端的檔案哦.
DECLARE @file VARCHAR(MAX) SET @file = 'D:\features'
--1.讀取檔案屬性到Table select * from dbo.FileInfo2Table(@file)
--2.讀取文字到Table select * from dbo.FileReadText2Table(@file)
-- 3.讀取文字 select dbo.FileReadText(@file)
測試結果:
六.SQL SERVER訪問共享目錄方法
採用SQL SERVER操作檔案是不允許操作區域網中的共享檔案的,若想實現的話需Windows模擬域帳號登入,另一篇文章有講到的。PCB 工程系統 模擬windows域帳號登入
以檔案複製為例程式碼如下:
/// <summary> /// 讀取文字 /// </summary> /// <param name="FilePath">檔案路徑</param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static string FileReadText (string FilePath) { try { IntPtr admin_token = IntPtr.Zero; if (WinLogonHelper.LogonUser (ref admin_token) != 0) { using (WindowsIdentity wid_admin = new WindowsIdentity (admin_token)) { using (WindowsImpersonationContext wic = wid_admin.Impersonate ()) { return File.ReadAllText (FilePath); } } } } catch (Exception) { return ""; } return ""; } public class WinLogonHelper { /// <summary> /// 模擬windows登入域 /// </summary> [DllImport ("advapi32.DLL", SetLastError = true)] public static extern int LogonUser (string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); public static int LogonUser (ref IntPtr phToken) { return WinLogonHelper.LogonUser ("使用者名稱", "域名", "密碼", 2, 0, ref phToken); } }