zoukankan      html  css  js  c++  java
  • 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");
               }
           }
       }
  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/waynechan/p/2746754.html
Copyright © 2011-2022 走看看