C#高级编程笔记(22至25章节)文件\注册表\权限\事务
22安全(using System.Security.Principal;)
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);//当前线程用户 var principal = WindowsPrincipal.Current as WindowsPrincipal; //window组成员 var identity = principal.Identity as WindowsIdentity; //用户,可用属性.name
24文件与注册表操作
- FileSystemInfo 表示任何文件系统对象的基类。
- FileInfo和File表示文件系统上的文件
- DirectoryInfo和Directory表示文件系统上的文件夹。
- Path这个类包含的静态成员可以用于处理路径名。
- DriveInfo它的属性和方法提供了指定驱动器的信息。
- System.MarshalByRefObject .NET类中用于远程操作的基对象类,允许在应用程序域之间编组数据。
属性
属性名称 | 属性作用 |
CreationTime | 文件或文件夹创建时间 |
DirectoryName(仅用于文件类) | 包含文件夹的完整路径名 |
Parent(仅用于文件夹类) | 指定子目录的父目录 |
Exists | 文件或文件夹是否存在 |
Extension | 文件的扩展名,对于文件夹它返回空白 |
FullName | 文件或文件夹的完整路径名 |
LastAccessTime | 最后一次的访问文件或文件夹的时间 |
LastWriteTime | 最后一次修改文件或文件夹的时间 |
Name | 文件或文件夹的名称 |
Roct(仅用于文件夹类) | 路径的根部分 |
Length(仅用于文件类) | 返回文件的大小(以字节为单位) |
操作方法
操作名称 | 操作作用 |
Create() | 创建给定名称的文件夹或空文件,对于FilenInfo,该方法会返回一个流对象,经便写入文件. |
Delete() | 删除文件或文件夹,对于文件夹,有一个可以递归的Delete选项 |
MoveTo() | 移动和/或重命名文件或文件夹 |
CopyTo() | (只适用于FieInfo类)复制文件,注意文件夹没有复制方法.如果复制完整的目录树,需要单独复制每一个文件,创建对应于旧文件夹的新文件夹 |
GetDirectories() | (只适用于DirectoryInfo)返回DirectoryInfo对象数组,该数组表示文件夹中包含的所有文件夹 |
GetFiles() | (只适用于DirectoryInfo)返回FilesInfo对象数组,该数组表示文件夹中包含的所有文件. |
EnumerateFiles() | 返回文件名的IEnumerable<string>,在返回整个列表之前,可以对列表中的项执行操作 |
GetFileSystemInfos() | (只适用于DirectoryInfo)返回FilesInfo和DirectoryInfo对象,它把文件夹中包含的所有对象表示为一个FileSystemInfo引用数组 |
流数数的操作方法有Open()、OpenRead()、OpenText()、OpenWrite()、Create()、CreateText()等方法,它们都是返回流对象。
Path类
path.Combine()//合并
FileProperties示例
try { string folderPath = txtBoxInput.Text; DirectoryInfo theFolder = new DirectoryInfo(folderPath);//得到 一个文件夹实例 if (theFolder.Exists)//检测存在 { DisplayFolderList(theFolder.FullName);//执行方法 return;//返回 } FileInfo theFile = new FileInfo(folderPath); //得到一个文件实例 if (theFile.Exists)//检测存在 { DisplayFolderList(theFile.Directory.FullName);//执行方法 int index = listBoxFiles.Items.IndexOf(theFile.Name);//文件属性 listBoxFiles.SetSelected(index, true); return;//返回 } throw new FileNotFoundException("没有文件或文件夹 " + "this name: " + txtBoxInput.Text); } catch (Exception ex) { MessageBox.Show(ex.Message); }
读取文件
- File.ReadAllText(路径,Encoding.ASCII)//使用ASCII打开目标文件
- File.ReadAllBytes()//返回字节数组
- File.ReadAllLines()//逐行语取字符串返回数组
写入文件
- File.WriteAllText(路径,字符串);//把字符串写入路径文件
FileSteam文件流
FileStream test =new FileStream(path,fileMode,FileAccess,FileShare) //相关参数见下表(以下值可以使用'|'进行合并使用)
枚举 | 值 |
path路径名 | 字符串路径 |
FileMode文件打开模式 | Append追加,Create覆盖新建,CreateNew新建(存在则报错),Open打开(没有则报错),OpenOrCreate新建与打开(没有新建并打开)Truncate清除内容打开(慎用) |
FileAccess文件访问权限 | Read读取,ReadWrite读取写入,Write写入 |
FileShare文件共享方式 | None独占,Read允许别的程序读取,Write允许别的程序写入,ReadWrite允许别的程序读取与写入 |
- FileSteam.ReadByte();//读取一个字节,返回0-255的整数,如果到达流的末尾则返回-1
- FileSteam.Read(ByteArray,0,nBytes);//把流写入一个ByteArray的字节数组中,参数0为偏移量,nBytes为字节数(参考网络传输文件),返回值为0时表示到达了流的末尾.
- FileSteam.WritByte();//把一个字节写入流中,没有返回值
- FileSteam.Writ(ByteArray,0,nBytes);//把一个字节数组写入流中,参数0为数组元素索引,后面为字节数,没有返回值
FileStream对象表示在磁盘或网络路径上指向文件的流。这个类提供了在文件中读写字节的方法,但经常使用StreamReader或 StreamWriter执行这些功能。这是因为FileStream类操作的是字节和字节数组,而Stream类操作的是字符数据。这是这两种类的一个重要区别,如果你是准备读取byte数据的话,用StreamReader读取然后用 System.Text.Encoding.Default.GetBytes转化的话,如下,则可能出现数据丢失的情况,如byte数据的个数不对等。因此操作byte数据时要用FileStream.
StreamReader类用于读取文本文件
- StreamReader sr = new StreamReader(FileStream实例);//FileStream(@"d:\123.txt",filemode.open,fileAccess.read)
- StreamReader sr = FileInfo实例.OpenText();
StreamReader方法 | 作用 |
ReadLine() | 读取一行 |
ReadToEnd() | 读取剩于的内容 |
Read() | 读取一个字符 |
StreamWriter类用于写入文本文件
- StreamWriter sw = new StreamWriter(@"D:\123.txt",true,Encoding.ASCII);以ASCII写入
- StreamWriter sw = new StreamWriter(FileStream实例);
- StreamWriter sw = FileInfo实例.CreateText();
24映射内存的文件
主要用于减少I/O的操作,让CPU直接操作储存,操作请查阅网上资料
24.6读取驱动器信息
DriveInfo [] di = DriveInfo.GetDrives(); //获取计算机驱动器数组,可以使用Froeach DriveInfo di1 = new DriveInfo(@"C:\");//获取C:\驱动器的实例
属性TotalSize总字节大小,TotalFreeSpace可用空间字节(为帐户磁盘配额),AvailableFreeSpace可用空间字节
24.7.1从文件中读取ACL(安全权限列表System.Security.AccessControl)
string myFilePath = @"D:\123.txt"; try { using (FileStream myFile = new FileStream(myFilePath, FileMode.Open, FileAccess.Read)) { FileSecurity fileSec = myFile.GetAccessControl(); foreach (FileSystemAccessRule fileRule in fileSec.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine("{0} {1} {2} 通道出口 {3}", myFilePath, fileRule.AccessControlType == AccessControlType.Allow ? "提供" : "拒绝", fileRule.FileSystemRights, fileRule.IdentityReference); } } } catch { Console.WriteLine("不正确的文件路径 !"); } /* 输出 D:\123.txt 拒绝 FullControl 通道出口 YJCN\qibobo D:\123.txt 提供 Modify, Synchronize 通道出口 NT AUTHORITY\Authenticated Users D:\123.txt 提供 FullControl 通道出口 NT AUTHORITY\SYSTEM D:\123.txt 提供 FullControl 通道出口 BUILTIN\Administrators D:\123.txt 提供 FullControl 通道出口 BUILTIN\Users */
24.7.1从目录中读取ACL
如上面示例相同,FileStream改为
DirectoryInfo myDir = new DirectoryInfo(mentionedDir); if (myDir.Exists) {DirectorySecurity myDirSec = myDir.GetAccessControl();程序2};//这里可以用myDirSec.GetAccessControl()
24.7.2添加ACL信息(加权限)
try { using (FileStream myFile = new FileStream(@"d:\123.txt", FileMode.Open, FileAccess.ReadWrite)) { FileSecurity filesec = myFile.GetAccessControl();//取得文件的权限列表 FileSystemAccessRule newRule = new FileSystemAccessRule(new System.Security.Principal.NTAccount(@"YJCN\liganwei"), FileSystemRights.FullControl, AccessControlType.Allow);//表示一条新的权限条目,其中YJCN\liganwei可以是域/帐户 或计算机名/帐户 filesec.AddAccessRule(newRule);//把上面的条目添加到列表中 File.SetAccessControl(@"d:\123.txt", filesec);//把权限列表应用到文件中 } } catch(ArgumentException ex) { Console.WriteLine(ex); }
24.8注册表
HKCR文件打开方式、 HKCU用户配置、 HKLM软件信息 注:软件一般存储在HKLM\Software\<CompanyName>键中
数据类型:REG_SZ(字符串), REG_DWORD(int类型), REG_BINARY(字节数组)
RegistryKey hklm = Registry.LocalMachine; RegistryKey hkSoftware = hklm.OpenSubKey("Software",true); //true表示写入权,无法写入注册表时,应该是注册表权限问题!把当前帐号加入权限 RegistryKey hkMine = hkSoftware.CreateSubKey("MyOwnSoftware");//在software目录下建立MyOwnSoftware目录 hkMine.SetValue("MyStringValue", "Hello World"); //在MyOwnSoftware目录建立REG_DWORD子项 hkMine.SetValue("MyIntValiue", 20); //在MyOwnSoftware目录建立REG_DWORD子项
//hkMine.DeleteValue();删除键值 或DeleteSubKey()
24.9 写入独立存储器(System.IO.IsolatedStorage)
创建(主要学习XML的创建)
IsolatedStorageFile storFile = IsolatedStorageFile.GetUserStoreForDomain(); //创建独立存储文件实例 IsolatedStorageFileStream storStream = new IsolatedStorageFileStream("SelfPlacingWindow.Xml", FileMode.Create, FileAccess.Write);//创建独立存储文件流 System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(storStream, Encoding.UTF8); //创建XmlTextWriter对象,以构建XMl文档, writer.Formatting = System.Xml.Formatting.Indented; //设置格式子元素缩进 writer.WriteStartDocument(); //写入版本号为1.0的XML声明 writer.WriteStartElement("Settings"); //开始标记 writer.WriteValue(12); //值 writer.WriteEndElement(); //结束标记 writer.Flush(); writer.Close(); storStream.Close(); storFile.Close();
读取(主要学习XML的读取)
IsolatedStorageFile storFile1 = IsolatedStorageFile.GetUserStoreForDomain(); //创建独立存储文件实例 String[] userFiles = storFile1.GetFileNames("SelfPlacingWindow.Xml"); //获取匹配文件名的文件,如果没带参数,返回所有 foreach (string userFile in userFiles) { if(userFile == "SelfPlacingWindow.Xml") //找到相应文件 { StreamReader storStream1 = new StreamReader(new IsolatedStorageFileStream("SelfPlacingWindow.Xml", FileMode.Open, storFile1)); //流读取文件 System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(storStream1); ////创建XmlTextReader对象,读取文档 while (reader.Read()) //读取下个节点 { switch (reader.Name) //节点限定名 { case "Settings": Console.WriteLine(reader.ReadString()); break; default: break; } } } } storFile1.Close(); userFiles.Clone();
25 事务
ACID属性
- A原子性
- C 一致性
- I 隔离性
- D 持久性
25.3 数据库和实体类
SqlConnection connection = new SqlConnection( Properties.Settings.Default.CourseManagementConnectionString); SqlCommand courseCommand = connection.CreateCommand(); courseCommand.CommandText ="INSERT INTO Courses (Number, Title) VALUES (@Number, @Title)"; await connection.OpenAsync(); SqlTransaction tx = connection.BeginTransaction(); //事务开始 try { courseCommand.Transaction = tx; //加入事务 courseCommand.Parameters.AddWithValue("@Number", course.Number); courseCommand.Parameters.AddWithValue("@Title", course.Title); await courseCommand.ExecuteNonQueryAsync(); tx.Commit(); //提交事务 } catch (Exception ex) { Trace.WriteLine("Error: " + ex.Message); tx.Rollback(); //回滚事务 throw; } finally { connection.Close(); }
25.4传统事务
SQLConnection类 BeginTransaction()开始事务, Commit()提交事务 Rollback() 回滚事务
25.4.2 System.EnterpriseServices 优点是自动登陆事务,要派生基类(少用)
25.5 System.Transaction
25.5.1可提交的事务
相关代码查阅书本
SqlConnection connection = new SqlConnection(Properties.Settings.Default.CourseManagementConnectionString); await connection.OpenAsync(); try { if (tx != null) connection.EnlistTransaction(tx); //检测事务是否有事务实例,把sql连接装入事务 .... wait command.ExecuteNonQueryAsync(); }
var tx = new CommittableTransaction(); try { await db.AddStudentAsync(s1, tx); tx.Commit(); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(); tx.Rollback(); }
25.5.2 事务处理的升级
代码与上示例相同,
await db.AddStudentAsync(s1, tx); await db.AddStudentAsync(s2, tx);//事务升级需要启动分布式事务协调器(DTC) 在windows服务里可以找到MS DTC
可以在设置超时时间!请查看书本
25.5.3依赖事务
static void DependentTransaction() { var tx = new CommittableTransaction(); //根事务 Utilities.DisplayTransactionInformation("TX创建根", tx.TransactionInformation); try { Task.Factory.StartNew(TxTask, tx.DependentClone(DependentCloneOption.BlockCommitUntilComplete)); //创建依赖事务Transaction.DependentClone 方法返回一个依赖事务,阻塞父事务 if (Utilities.AbortTx()){throw new ApplicationException("transaction abort");} tx.Commit(); //尝试提交事务 } catch (Exception ex) { Console.WriteLine(ex.Message); tx.Rollback(); //回滚事务 } Utilities.DisplayTransactionInformation("TX 完成了",tx.TransactionInformation); } static void TxTask(object obj) { var tx = obj as DependentTransaction; Utilities.DisplayTransactionInformation("相关事务",tx.TransactionInformation); Thread.Sleep(3000); tx.Complete();//尝试完成依赖事务 Utilities.DisplayTransactionInformation("相关TX完成",tx.TransactionInformation); }
25.5.4环境事务
事务完成时的事件设置调用OnTransactionCompleted方法,因为SQLConnection支持环境事务,并且会自动通过连接登记它
static async Task TransactionScopeAsync() { using (var scope = new TransactionScope()) { Transaction.Current.TransactionCompleted += OnTransactionCompleted; //为环境事务的TransactionCompleted完成事件加入OnTransactionCompleted方法 Utilities.DisplayTransactionInformation("Ambient TX created", Transaction.Current.TransactionInformation); var s1 = new Student { FirstName = "Angela",LastName = "Nagel",Company = "Kantine M101"}; var db = new StudentData(); await db.AddStudentAsync(s1); if (!Utilities.AbortTx()) scope.Complete();//指示范围中的所有操作都已成功完成。 else Console.WriteLine("transaction will be aborted"); } // scope.Dispose();这里代表结束事务,如果没调用Complete()方法,就应该调Dispose()方法结束事务 } static void OnTransactionCompleted(object sender, TransactionEventArgs e) { Utilities.DisplayTransactionInformation("TX completed",e.Transaction.TransactionInformation); }
1嵌套的作用域和环境事务
TransactionScopeOption枚举的值:
- Required(需要的)嵌套的事务要提交后才生效
- Required(新的事务)二个独立的事务
- Suppress(取消事务)
2多线程与环境事务
try { using (var scope = new TransactionScope()) { Transaction.Current.TransactionCompleted += TransactionCompleted; //完成时输出 Utilities.DisplayTransactionInformation("Main thread TX",Transaction.Current.TransactionInformation); Task.Factory.StartNew(TaskMethod, Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete));//创建依赖事务,如果这里没有依赖事务选项,则因是不同的线程,所以是二个不同的事务 scope.Complete(); } } catch (TransactionAbortedException ex) { Console.WriteLine("Main—Transaction was aborted, {0}",ex.Message); }
25.6隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
ReadUncommitted (可读取修改可变数据) | Y | Y | Y |
ReadCommitted (可读取不可修改可变数据) | N | Y | Y |
RepeatableRead (可读取不可修改可变数据,可添加) | N | N | Y |
Serializable (可读取不可修改可变数据,不可添加) | N | N | N |
var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted,Timeout = TimeSpan.FromSeconds(90) //设置事务可读可修改可变数据,超时设置为90毫秒 }; using (var test = new TransactionScope(TransactionScopeOption.Required, options)) { }
25.7自定义资源管理器
此节涉及"浅拷贝"与"深拷贝"的相关知识 请先查看 相关的知识点
因理解问题,以下是Transactions的所有代码注释
using System; using System.Diagnostics; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Transactions; namespace Wrox.ProCSharp.Transactions { public class Transactional<T> { private T liveValue; //实时值 private ResourceManager<T> enlistment; //临时值 private Transaction enlistedTransaction; //事务 public Transactional(T value) { if (Transaction.Current == null) { this.liveValue = value; } else { this.liveValue = default(T); GetEnlistment().Value = value; } } public Transactional(): this(default(T)) { } /// <summary> /// 检测是否在环境事务中,如果有 /// </summary> /// <returns></returns> private ResourceManager<T> GetEnlistment() { Transaction tx = Transaction.Current; //获取环境事务 Trace.Assert(tx != null, "必须用环境事务调用");//检查条件;如果条件为 false,则输出消息并显示一个消息框,后者用于显示调用堆栈。 if (enlistedTransaction == null)//如果没有登记事务 { enlistment = new ResourceManager<T>(this, tx); //实例化内部类 tx.EnlistVolatile(enlistment, EnlistmentOptions.None); //登记事务 enlistedTransaction = tx; return enlistment; } else if (enlistedTransaction == Transaction.Current) //查看是否是在同一线程中4 { return enlistment; //返回资源管理器 } else { throw new TransactionException("此类仅支持与一个事务一起使用的列表"); } } public T Value { get { return GetValue(); } set { SetValue(value); } } protected virtual T GetValue() { if (Transaction.Current == null) { return liveValue; } else { return GetEnlistment().Value; } } protected virtual void SetValue(T value) { if (Transaction.Current == null) { liveValue = value; } else { GetEnlistment().Value = value; } } /// <summary> /// 提交事务的方法 /// </summary> /// <param name="value"></param> /// <param name="tx"></param> internal void Commit(T value, Transaction tx) { liveValue = value; enlistedTransaction = null; } /// <summary> /// 回滚事务的方法 /// </summary> /// <param name="tx"></param> internal void Rollback(Transaction tx) { enlistedTransaction = null; } internal class ResourceManager<T1> : IEnlistmentNotification //内部类,只有当前项目可以访问 { private Transactional<T1> parent; //临时值() public T1 Value { get; set; } //实时值 private Transaction currentTransaction;//事务 internal ResourceManager(Transactional<T1> parent, Transaction tx) { this.parent = parent; Value = DeepCopy(parent.liveValue);//序列化"parent.liveValue" currentTransaction = tx;//事务 } static ResourceManager() { Type t = typeof(T1);//获取类型类型 //Assert方法检查条件;如果条件为 false,则输出消息并显示一个消息框,后者用于显示调用堆栈。 Trace.Assert(t.IsSerializable, "Type " + t.Name + " 不可串行化");//Type.IsSerializable 属性如果可序列化则为 true;否则为 false。 } /// <summary> /// 序列化对象到流中 /// </summary> /// <param name="value">对象</param> /// <returns></returns> private static T1 DeepCopy(T1 value) { using (var stream = new MemoryStream()) { var formatter = new BinaryFormatter();//以二进制格式将对象或整个连接对象图形序列化和反序列化。 formatter.Serialize(stream, value);//序列化value到stream流中 stream.Flush();//当重写Flush方法时,将清除该流的所有缓冲区,并使得所有缓冲数据被写入到基础设备 stream.Seek(0, SeekOrigin.Begin);//将当前流中的位置设置为指定值。 return (T1)formatter.Deserialize(stream);//返回 将流反序列化为对象图形。 } } public void Prepare(PreparingEnlistment preparingEnlistment) { preparingEnlistment.Prepared(); } public void Commit(Enlistment enlistment) { parent.Commit(Value, currentTransaction); enlistment.Done(); } public void Rollback(Enlistment enlistment) { parent.Rollback(currentTransaction); enlistment.Done(); } public void InDoubt(Enlistment enlistment) { enlistment.Done(); } } } }
ng System; using System.Diagnostics.Contracts; using System.Transactions; namespace Wrox.ProCSharp.Transactions { public static class Utilities { public static bool AbortTx() { Console.Write("中止事务 (y/n)?"); return Console.ReadLine().ToLower().Equals("y"); } public static void DisplayTransactionInformation(string title, TransactionInformation ti) { if (ti == null) { throw new Exception("事务不能为空"); } Console.WriteLine(title); Console.WriteLine("创建 Time: {0:T}", ti.CreationTime); Console.WriteLine("状态: {0}", ti.Status); Console.WriteLine("本地 ID: {0}", ti.LocalIdentifier); Console.WriteLine("分布式 ID: {0}", ti.DistributedIdentifier); Console.WriteLine(); } } }
以上是理解主要在于添加了接口与序列化的问题!请细心解读
25.8文件事务
因此节涉及COM的相关知识,这里不做解读!!直接拿着用吧!!在代码中加下面类
using System; using System.Runtime.InteropServices; namespace Wrox.ProCSharp.Transactions { [ComImport] [Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IKernelTransaction { void GetHandle(out SafeTransactionHandle ktmHandle); } }
using System; using System.Security; using System.Security.Permissions; using System.Security.AccessControl; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; namespace Wrox.ProCSharp.Transactions { [SecurityCritical] internal static class NativeMethods { [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)] internal static extern SafeFileHandle CreateFileTransacted( String lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile, SafeTransactionHandle txHandle, IntPtr miniVersion, IntPtr extendedParameter); [DllImport("Kernel32.dll", SetLastError = true)] [ResourceExposure(ResourceScope.Machine)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); } }
using System; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Microsoft.Win32.SafeHandles; namespace Wrox.ProCSharp.Transactions { [SecurityCritical] internal sealed class SafeTransactionHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeTransactionHandle(): base(true) { } //安全事务句柄 public SafeTransactionHandle(IntPtr preexistingHandle, bool ownsHandle): base(ownsHandle) { SetHandle(preexistingHandle); } [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] protected override bool ReleaseHandle() { return NativeMethods.CloseHandle(handle); } } }
using System; using System.IO; using System.Security.Permissions; using System.Transactions; using Microsoft.Win32.SafeHandles; namespace Wrox.ProCSharp.Transactions { public static class TransactedFile { internal const short FILE_ATTRIBUTE_NORMAL = 0x80; internal const short INVALID_HANDLE_VALUE = -1; internal const uint GENERIC_READ = 0x80000000; internal const uint GENERIC_WRITE = 0x40000000; internal const uint CREATE_NEW = 1; internal const uint CREATE_ALWAYS = 2; internal const uint OPEN_EXISTING = 3; [FileIOPermission(SecurityAction.Demand, Unrestricted = true)] public static FileStream GetTransactedFileStream(string fileName) { IKernelTransaction ktx = (IKernelTransaction) TransactionInterop.GetDtcTransaction(Transaction.Current); SafeTransactionHandle txHandle; ktx.GetHandle(out txHandle); SafeFileHandle fileHandle = NativeMethods.CreateFileTransacted( fileName, GENERIC_WRITE, 0, IntPtr.Zero, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero, txHandle, IntPtr.Zero, IntPtr.Zero); return new FileStream(fileHandle, FileAccess.Write); } } }
调用方法如下:
using System; using System.IO; using System.Transactions; namespace Wrox.ProCSharp.Transactions { class Program { static void Main() { WriteFileSample(); } static async void WriteFileSample() { using (var scope = new TransactionScope()) { FileStream stream = TransactedFile.GetTransactedFileStream("sample.txt"); var writer = new StreamWriter(stream); await writer.WriteLineAsync("Write a transactional file"); writer.Close(); if (!Utilities.AbortTx()) scope.Complete(); } } } }