zoukankan      html  css  js  c++  java
  • C# IO操作(四)大文件拷贝(文件流的使用)、文件编码

         大文件拷贝(文件流的使用)、文件编码

    首先说一下大文件拷贝和文件流,因为计算机的内存资源是有限的,面对几个G甚至更大的文件,需要通过程序来完成拷贝,就需要用到文件流(因为我们无法做到把文件一次性加载到内存中;事实上,内存也不允许这么干),所以在C#中出现了内存流这个东西。先看下面的内容,File类中的常用读取文件方法会将文件内容一次性全部加载到内存中

    1             string sPath = @"C:UsersChens-PCDesktopNginx.txt";
    2             //File类的ReadAllBytes()方法会将文本内容一次性读取到内存中,然后以byte数组返回(同时关闭文件)。
    3             byte[] bteData = File.ReadAllBytes(sPath);
    4             //File类的ReadAllLines()方法会将文本内容一次性逐行读取到内存中,然后以string数组返回(同时关闭文件),它的重载能指定读取时使用的编码。
    5             string[] strData = File.ReadAllLines(sPath);
    6             //File类的ReadAllText()方法会将文本内容一次性读取到内存中,然后以string字符串返回(同时关闭文件),它的重载能指定读取时使用的编码。
    7             string sData = File.ReadAllText(sPath);

    注:上面的代码,在传参时为Encoding.Default(表示与当前操作系统编码一致,一般是简体中文ANSI),而DotNet新建文本文件编码为UTF-8.

    在进行大文件拷贝之前,先说一下,如果使用文件流(FileStream):

     1            #region 通过文件流写文件
     2             string sMsg = "风儿吹来了童年的一幅画 你陪着我在那过家家 竹林是我们的家 竹叶是你送我的花 抬头见你笑得那么的无暇";
     3             using (FileStream fsWrite = new FileStream("msg.txt", FileMode.Create, FileAccess.Write))
     4             {
     5                 byte[] bteData = System.Text.Encoding.UTF8.GetBytes(sMsg);
     6                 fsWrite.Write(bteData, 0, bteData.Length);
     7                 fsWrite.Flush();
     8             }
     9             Console.WriteLine("文件写入完毕!");
    10             #endregion
     1             #region 通过文件流读文件
     2             using (FileStream fsRead = new FileStream("msg.txt", FileMode.Open, FileAccess.Read))
     3             {
     4                 byte[] bteData = new byte[fsRead.Length];
     5                 fsRead.Read(bteData, 0, bteData.Length);
     6                 //将byte[]数组转换成字符串时才需要指定编码。
     7                 string s = System.Text.Encoding.UTF8.GetString(bteData);
     8                 Console.WriteLine(s);
     9             }
    10             #endregion

    1.大文件拷贝:

         思路:考虑到大文件的拷贝要边读边写,故要创建2个文件流(一个读,一个写),案例的代码如下(winform照样适用):

    1              #region 大文件拷贝
    2             string sSource = @"F:系统cn_windows_7_ultimate_with_sp1_x86_dvd_618763.iso";
    3             string sTarget = @"E:C#练习第一天windows_7.iso";
    4 
    5             CopyBigFile(sSource, sTarget);
    6             Console.ReadKey();
    7             #endregion
    View Code
     1 private static void CopyBigFile(string sSource, string sTarget)
     2         {
     3             using (FileStream fsRead=new FileStream(sSource,FileMode.Open,FileAccess.Read))
     4             {
     5                 using (FileStream fsWrite=new FileStream(sTarget,FileMode.Create,FileAccess.Write))
     6                 {
     7                     //定义缓冲区
     8                     byte[] bteData = new byte[12 * 1024 * 1024];
     9                     int r = fsRead.Read(bteData, 0, bteData.Length);
    10                     while (r>0)
    11                     {
    12                         fsWrite.Write(bteData, 0, r);
    13                         double d = 100 * (fsWrite.Position / (double)fsRead.Length);
    14                         Console.WriteLine("{0}%", d);
    15                         r = fsRead.Read(bteData, 0, bteData.Length);
    16                     }
    17                     Console.WriteLine("复制大文件成功");
    18                 }
    19             }
    20         }
    View Code

    说明:

    快速创建文件流的方式:(不要在循环中创建文件流,放在循环外,效率问题)
         FileStream fsRead=File.OpenRead(sPath);    //快速创建读取流
         FileStream fsWrite=File.OpenWrite(sPath);         //快速创建写入流
         FileStream fs=File.Open(sPath,FileMode.OpenOrCreate);    //创建文件流

    上面的3个方法只是微软对(大文件拷贝中创建文件流方法的封装,简化代码编写的方式)。

    最后再来讨论文件读写乱码的问题(文件编码):

    下面是常用的文本文件编码:

         1.GB2312编码:兼容ASCII码表,英文字符用1个字节表示(字节用正数来表示),中文用2个字节表示(字节用负数来表示)。
         2.GBK编码:兼容GB2312编码。中文用2个字节表示(第1个字节用负数,第2个字节用紧跟其后的正数)。
         3.Unicode:国际码表,中英文都占2个字节。
         4.UTF-8:国际码表,英文占1个字节,中文占3个字节。
    因为各种编码存储数据格式不一致,如果读写编码不同就会乱码,解决乱码的途径就是让读写操作时保证编码一致即可

    文件编码的BOM头:

         时常在读取文件时用文件的编码,有时前面会多一个问号,这是因为BOM头造成的File.ReadAllBytes().(不准确,有的编码带BOM头,有的则不带)

    2.StreamReader与StreamWriter
     应用场景:在使用FileStream进行大文件拷贝的时候,因为中文占2个字节,那么有可能产生读汉字读一半的情况,进而产生乱码。
     StreamReader,逐行读取文本文件。ReadLine()、EndOfStream. 注意:指定编码!

                ReadToEnd用于从当前位置一直读到最后,内容大的话会占内存;每次调用都往下走,不能无意中调用了两次.

                ReadLine读取一行,如果到了末尾,则返回null.


     StreamWriter,逐行写入文本文件。

          WriteLine,将字符串写入文件中的当前行。

    3.压缩流GZipStream:

    1>压缩:
         1.创建读取流File.OpenRead()
         2.创建写入流File.OpenWrite();
         3.创建压缩流new GZipStream();将写入流作为参数与。
         4.每次通过读取流读取一部分数据,通过压缩流写入。
     1             //GZipStream就是对FileStream的又一个包装
     2             //将文本文件1.txt压缩
     3             //1.创建读取文本文件的流
     4             using (FileStream fsRead = File.OpenRead("1.txt"))
     5             {
     6                 //2.创建写入文本文件的流
     7                 using (FileStream fsWrite = File.OpenWrite("yasuo.txt"))
     8                 {
     9                     //3.创建压缩流
    10                     using (GZipStream zipStream = new GZipStream(fsWrite, CompressionMode.Compress))
    11                     {
    12                         //4.每次读取1024byte
    13                         byte[] byts = new byte[1024];
    14                         int len = 0;
    15                         while ((len = fsRead.Read(byts, 0, byts.Length)) > 0)
    16                         {
    17                             //通过压缩流写入文件
    18                             zipStream.Write(byts, 0, len);
    19                         }
    20                     }
    21                 }
    22             }
    23             Console.WriteLine("ok");
    24             Console.ReadKey();

    2>解压:

           1.创建读取流:File.OpenRead()
           2.创建压缩流:new GZipStream();将读取流作为参数
           3.创建写入流File.OpenWrite();
           4.每次通过压缩流读取数据,通过写入流写入数据。
     1  using (FileStream fsRead = File.OpenRead("yasuo.txt"))
     2             {
     3 
     4                 using (GZipStream gzipStream = new GZipStream(fsRead, CompressionMode.Decompress))
     5                 {
     6                     using (FileStream fsWrite = File.OpenWrite("jieya.txt"))
     7                     {
     8 
     9                         byte[] byts = new byte[1024];
    10                         int len = 0;
    11                         while ((len = gzipStream.Read(byts, 0, byts.Length)) > 0)
    12                         {
    13                             fsWrite.Write(byts, 0, len);
    14                         }
    15 
    16                     }
    17                 }
    18             }
    19             Console.WriteLine("ok");
    20             Console.ReadKey();
  • 相关阅读:
    Socket与系统调用深度分析
    AudioRecord::getMinFrameCount
    c++: address argument to atomic operation must be a pointer to _Atomic type
    python秒表,方便测试计时
    Android驱动笔记(13)——PMIC reset介绍
    Android驱动笔记(10)——DOS或BAT脚本语法
    第八章——Linux设备模型(1)
    第四章——IOCTL(1)
    第三章(扩展)——虚拟串口设备
    第三章——字符驱动设备
  • 原文地址:https://www.cnblogs.com/chens2865/p/3886077.html
Copyright © 2011-2022 走看看