好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

IO流操作实现文件拷贝\简单加密及相关知识点

IO流操作实现文件拷贝\简单加密及相关知识点

直接搬起水缸抬水

文件的拷贝类似于从一个水缸中把水运到另外一个水缸,如果水缸小且水少(文件容量小)我们可以直接把水缸抬起来,把水直接倒进另外一个水缸中,这种方式的好处是:快,但是缺点是一旦水缸稍大你就抬不动它了(消耗系统内存,效率低),所以在此我不建议使用,而这种方式在流中的表现形式是:

 private   void   FileCopy()
 {
            byte [] bytes = File.ReadAllBytes( @"  C:\1.txt  "  );
          File.WriteAllBytes(  @"  C:\2.txt  "  , bytes);
 } 

使用合适的勺子

当一个水缸足够大的时候,我们就要使用一些方法来帮助我们多快好省的完成运水(文件拷贝)的工作了,这时候,一把容量适合的勺子正和我意;

 static   void  Main( string  [] args)
       {
             using  (FileStream outStream =  new  FileStream( @"  C:\2.zip  "  , FileMode.Create))
           {
                 using  (FileStream fs =  new  FileStream( @"  C:\1.zip  "  , FileMode.Open))
               {
                     //  缓冲区太小的话,速度慢而且伤硬盘
                     //  声明一个4兆字节缓冲区大小,比如迅雷也有一个缓冲区,如果没有缓冲区的话,
                     //  每下载一个字节都要往磁盘进行写,非常伤磁盘,所以,先往内存的缓冲区写字节,当
                     //  写够了一定容量之后,再往磁盘进行写操作,减低了磁盘操作。 
                    byte [] bytes =  new   byte [ 1024  *  1024  *  4  ];
                     int   readBytes;
                     //  第二个参数Offset表示当前位置的偏移量,一般都传0 
                    while  ((readBytes = fs.Read(bytes,  0 , bytes.Length)) >  0 )  //  读取的位置自动往后挪动。 
                    {
                         //  readBytes为实际读到的byte数,因为最后一次可能不会读满。 
                       outStream.Write(bytes,  0  , readBytes);
                   }
               }
           }
           Console.WriteLine(  "  拷贝成功  "  );
       } 

 

代码实现的效果是,加入一个文件有10M,当第一次循环的时候读取4M,然后写到2.zip中,循环第二次如此,当第三次的时候,读取剩余的2M,继续写到2.zip中,完成文件拷贝的工作。
值得注意的地方是:
1、1.zip是已存在的文件,以FileMode.Open的方式将数据读取到byte[]数组中;
2、while循环中,每次最多读取1024 * 1024 * 4 字节,这我称作是缓冲区大小;
3、当读到最后一次的时候,byte[]数组可能不满,这时,readBytes将是byte[]实际的容量
4、while循环读取的时候,流中的seek或者是position会自动偏移处理,所以这并需要我们维护读取开始的位置

简单加密的思路

其实这里说是加密,我都不是很好意思说出口了,呵呵,透过byte.MaxValue我们知道,字节的最大值为255,所以,我们循环读取出来的字节数组,用255减去数组中的字节数值,用此值来保存,拷贝完毕之后,你会发现,这个文件根本是不能打开的或者是乱码,因为数据都已经被扰乱了,这相当于一个简单的加密效果,那如何去解密呢?将“加密”过的文件重新“拷贝”一次,经过255减去字节的值会得到原来真正的字节数组值,这相当于一个解密。

 //  对byte数组进行加密,byte的MaxValue为255,所以可以在这里做手脚 
  for  ( int  i =  0 ; i < readBytes; i++ )
   {
      bytes[i]  = ( byte )( byte .MaxValue -  bytes[i]);
   } 

流相关知识

1、Flush()-Close()-Dispose()过程
不知道大家有没有发现,我们使用流操作的时候,一定要Using(),如果你不Using资源,往文本txt中写入少量数据的时候,你会发现并没有写入成功,其实,流中有一个缓冲区,相当于上例中的byte[]数组,当你往文件写入数据的时候,流只是答应了你会写,但是什么时候写呢?他说了算,他可能让数据达到一定的大小的时候就会帮你写进去,但是,我们就要写这么少数据怎么办?你可以使用Flush()方法,意为强制把缓冲区中的数据写入到文件。Using在内部其实是走了这样的一个顺序:Flush()-Close()-Dispose()

2、压缩流 GZipStream
问:什么情况下,一个100M的txt文件会压缩到很小很小,就只有几百K的大小呢?
答:文本里存在大量大量的相同的字符串的时候,压缩率往往会很高,你没可能将一部1G的电影压缩到几百K吧。

        //  压缩流,如果直接存储相同的数据(如很多个很多个相同的字符串)
         //  使用FileStream会原样输出保存,数据量很大,我们可以使用GzipStream进行压缩保存,减少存储空间 
        private   void   CompressStream()
       {
             string  s =  "  DotNetGeek  "  ;
             for  ( int  i =  0 ; i <  100 ; i++ )
           {
               s  +=  s;
           }
             using  (FileStream fs =  new  FileStream( @"  C:\1.txt  "  , FileMode.Create))
           {
                 using  (GZipStream gs =  new   GZipStream(fs, CompressionMode.Compress))
               {
                     byte [] bytes =  Encoding.UTF8.GetBytes(s);
                   gs.Write(bytes,   0  , bytes.Length);
               }
           }
       } 

3、解压流
有压缩流就有解压流

 private   void   DeCompressStream()
{
      using  (FileStream fs =  new  FileStream( @"  C:\2.txt  "  , FileMode.Open))
    {
          using  (GZipStream zipStream =  new   GZipStream(fs, CompressionMode.Decompress))
        {
              using  (FileStream outputStream =  new  FileStream( @"  C:\unzip2.txt  "  , FileMode.Create))
            {
                  int   bytesRead;
                  byte [] bytes =  new   byte [ 1024  ];
                  while  ((bytesRead = zipStream.Read(bytes,  0 , bytes.Length)) >  0  )
                {
                    outputStream.Write(bytes,   0  , bytesRead);
                }
            }
        }
    }
} 

自己好好理解一些代码运行的调用顺序

4、内存流 MemoryStream
内存流 MemoryStream ,将数据以流的形式存储在内存中

 private   void   MemoryStreamFun()
{
    MemoryStream ms  =  new   MemoryStream();
      string  s =  "  hello  "  ;
      byte [] bytes =  Encoding.UTF8.GetBytes(s);
    ms.Write(bytes,   0  , bytes.Length);
} 

5、文本处理方便的StreamReader

如果我们的需求是简单对文本进行流的操作,我们大可不必使用FileStream繁琐的操作,又是2个流还while循环的,DotNet为我们准备了一个专门用来处理文本的流;

 //  如果是读取文本流,就可以使用StreamReader来简化操作 
    private   void   StreamReaderFn()
   {
         using  (Stream stream = File.OpenRead( @"  C:\1.txt  "  ))
       {
             using  (StreamReader reader =  new   StreamReader(stream))
           {
                 string   s;
                 while  ((s = reader.ReadLine()) !=  null  )
               {
                     //  假如文本里有三行数据,则每次读一行,循环三次读取完毕,如果没有数据返回null
                     //  指针自动下移,和SqlDataReader.Read类似 
                    Console.WriteLine(s);
               }

               s  =  reader.ReadToEnd();
                 //  一次性读取出来(数据量少的情况) 
            }
       }
   }

     private   void   StreamWriterFn()
   {
         using  (FileStream fs = File.OpenWrite( @"  C:\1.txt  "  ))
       {
             using  (StreamWriter writer =  new   StreamWriter(fs))
           {
               writer.WriteLine(  "  hello  "  );
               writer.WriteLine(  "  world  "  );
           }
       }
   } 

作者:  陈华惠  
出处:  http://www.dotnetgeek.cn  
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  ASP.NET

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于IO流操作实现文件拷贝\简单加密及相关知识点的详细内容...

  阅读:31次