C# - 大文件拷贝与加密/解密,using的本质 100
小文件拷贝
文件比较小:指的是要拷贝的文件不需要通过使用循环进行多次读写操作
static void Main(string<> args){ #region 小文件拷贝(文件本身 3KB) //1. 创建1个文件流对象,指定操作的文件(路径) 与文件操作方式 FileStream fsRead = new FileStream(@"d:test\2.txt", FileMode.Open); //2. 准备1个byte数组(就是中间的缓冲区) //用于存储文件流对象读取的数据 //缓冲区设置为2KB byte<> buffer = new byte<1024 * 2>; //3. 调用文件流对象的读取方法 //将读出来的字节放入到buffer数组中. fsRead.Read(buffer, 0, buffer.Length); //4. 创建写入文件的文件流对象 //参数1 设置要写入的文件路径 //参数2 操作文件的方式是创建新文件(如有此文件,就覆盖掉旧有文件) FileStream fsWrite = new FileStream(@"d:\test\7.txt", FileMode.Create); //5. 调用文件流对象的写入方法 //参数1 缓冲区的字节数组 //参数2 从缓冲区索引为0的地方开始 //参数3 写入的实际字节数(小于等于缓冲区的大小) fsWrite.Write(buffer, 0,buffer.Length); //6.关闭文件流,释放占用的资源 //关闭/释放读取对象 fsRead.Close(); fsRead.Dispose(); //关闭/释放写入对象 fsWrite.Close(); fsWrite.Dispose(); Console.WriteLine("小文件拷贝完毕"); Console.ReadKey(); #endregion}
using的本质
using的作用之一:之前说过可用于引用命名空间,方便使用其空间下各类的属性与方法
using的作用之二:被using包裹的对象,会在对象出了大括号的范围后自动调用对象的Dispose()方法(即使using内部使用的return语句)
using的语法格式
using(文件流){ 调用文件流对象的读写方法}//超过大括号(即作用域范围)//系统就自动调用Dispose()方法
自己定义一个Person,使用using进行包裹报错
报错原因在于:Person类没有实现IDisposable接口,无法继承接口的Dispose()方法,因此超过using包裹的作用域时系统就无法调用对象 p 的Dispose();
言下之意就是被using包裹的类必须实现IDisposable接口,才能调用其Dispose()方法
class Program{ static void Main(string<> args) { using (Person p = new Person()) { Console.WriteLine("对象 p 被 using包裹"); } Console.WriteLine("对象 p 出了 using 的范围"); Console.ReadKey(); }}//实现接口(就是类继承接口的说法)//IDisposable接口中只有一个Dispose()方法//光标放在IDisposable上,按F12可查看public class Person : IDisposable{ public void Say() { Console.WriteLine("普通方法"); } #region IDisposable 成员 public void Dispose() { Console.WriteLine("被对象 p 调用了Dispose() 释放所占用的资源"); } #endregion}
通过VS自带的反编译工具查看using的本质就是try-finally语句;在try语句块中就是using中的代码,在finally语句块中会自动调用Dispose();
一定调用Dispose()的原因是它在finally语句块中,之前的异常处理中说过,不管try语句块最终是否执行,finally语句块中的代码最后一定会执行
大文件拷贝
需要通过循环读取缓冲区中的字节,进行多次的读写操作
示例:大文件容量大约200MB,缓冲区设置为20MB
static void Main(string<> args){ //实例化读取文件流对象 using (FileStream fsRead = new FileStream(@"D:\test\1.zip", FileMode.Open)) { //实例化写入文件流对象 using (FileStream fsWrite = new FileStream(@"D:\test\2.zip", FileMode.Create)) { //设置缓冲区为 20MB byte<> buffer = new byte<1024 * 1024 *20>; //源文件的总容量(1.zip) long countLen = fsRead.Length; //通过死循环读写文件 while (true) { //读取缓冲区大小的字节数据 int r = fsRead.Read(buffer, 0, buffer.Length); //设置退出死循环的条件 //如果当前读取的字节数大于0就写入文件 if (r > 0) { //写入缓冲区大小的字节数据 fsWrite.Write(buffer, 0, buffer.Length); //已写入的容量 long writeLen = fsWrite.Length; //文件写入进度 double proc = (double)writeLen / countLen; Console.WriteLine("拷贝进度 {0:0.00}%",proc*100); } else { //退出死循环 break; } } } } Console.WriteLine("大文件拷贝完毕"); Console.ReadKey();}
可将其提取为一个方法(参数1:源文件,参数2:目标文件)
加密/解密文件
就是改变每个字节的值,读取的字节数组中每个字节都是0-255的数
此次使用的加密原理是:通过循环让字节数组中的每个字节都进行255-当前字节的值;解密就是将其倒装回来
//假设读取到的当前字节数据byts<0>=100;byts<1>=200;byts<3>=235;//使用255-每个字节进行加密byts<0>=255-100; byts<1>=255-200;byts<3>=255-235;//加密后的数据为byts<0>=155;byts<1>=55;byts<3>=20;//解密 就是使用255减去加密过的数据
其他方式:如将其中的某些字节在0-255之间进行操作
byts<2>=10;//"加密"第二个字节byts<78>=160;//"加密"第78个字节byts<189>=230;//"加密"第189个字节//将其中一些字节进行"加密"使用255-当前字节的数据//加密后的数据byts<2>=245;byts<78>=95;byts<189>=25;//解密同上
将加密/解密提取为一个方法,加密/解密时只需要将源文件与目标文件的位置进行互换即可
/// <summary>/// 加密/解密文件/// </summary>/// <param name="sourse">源文件</param>/// <param name="terget">加密/解密后的文件</param>/// <param name="bufLength">设置缓冲区的大小</param>static void EncrypAndDecryp(string sourse, string terget, int bufLength){ //实例化读取文件流对象 using (FileStream fsRead = new FileStream(sourse, FileMode.Open)) { //实例化写入文件流对象 using (FileStream fsWrite = new FileStream(terget, FileMode.Create)) { //设置缓冲区 byte<> buffer = new byte; //通过循环读写文件 while (true) { //读取缓冲区大小的字节数据 int r = fsRead.Read(buffer, 0, buffer.Length); //将所有的数据都通过循环进行"加密" for (int i = 0; i < buffer.Length; i++) { //byte.MaxValue字节类型的最大值即 255 //byte.MaxValue - buffer结果是 int类型 buffer = (byte)(byte.MaxValue - buffer); } //设置退出死循环的条件 //如果当前读取的字节数大于0就写入文件 if (r <= 0) { //退出死循环 break; } else { //写入缓冲区大小的字节数据 fsWrite.Write(buffer, 0, buffer.Length); } } } }}//调用方法static void Main(string<> args){ string sourse = @"D:\test\2.txt"; string terget = @"D:\test\8.txt"; int buflen = 1024; //进行加密 EncrypAndDecryp(sourse, terget, buflen); Console.WriteLine("加密到 8.txt"); //进行解密,解密到新文件 EncrypAndDecryp(terget, @"D:\test\9.txt", buflen); Console.WriteLine("解密到 9.txt"); Console.ReadKey();}