黑马程序员----字符流,字节流,二进制序列化的使用及区别

时间:2023-01-11 17:08:07

   概念与理解:


  字符流及字节流:

     文件(实际的物理存储形式:字节)-----字节流(按照一个字节,八个二进制位读取,写入)-----字符流(按照指定或系统默认的编码(utf8)读取16位二进制数,两个字节并将其编码为字符)-----内存中的字符(虚拟的抽象的表现形式:字符)

     文件的存储及数据的传输都是以字节的形式,只有当需要在内存中操作时才需要字符流,字符只存在于内存中。

    字节流和字符流的使用:

     当操作的对象不需要关心编码的问题,如图像,声音等二进制数据的拷贝,传送。或需要文件加密时,(不需再内存中操作),应使用字节流。

      当需要关心编码的问题(需要在内存中操作),应使用字符流。


       序列化:

      文件----字节流-----序列化-----内存中的类,对象,包括数组,结构等。

     .NET Framework 提供两种序列化技术: 

    序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,就使得数据能够被轻松地存储和传输。

        公共语言运行库管理对象在内存中的布局方式并通过使用反射提供自动的序列化机制。当序列化一个对象时,类的名称、程序集和类实例的所有数据成员都被写入存储中。对象通常在成员变量中存储对其他实例的引用。在序列化类时,序列化引擎跟踪所有已被序列化的引用的对象,以确保同一对象不会被多次序列化。随 .NET Framework 一起提供的序列化结构自动正确处理对象图和循环引用。对于对象图的唯一要求就是,由正被序列化的对象引用的所有对象还必须被标记为 Serializable(基本序列化)。如果没有进行此标记,当序列化程序尝试序列化未标记的对象时,将引发一个异常。
当反序列化已序列化的类时,重新创建该类并且自动还原所有数据成员的值。



   1 二进制序列化保持类型保真度,将一个复杂的对象转换流,方便我们的存储与信息交换,对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享该对象。可将对象序列化到流、磁盘和内存等,还可以通过网络序列化对象。远程处理使用序列化“通过值”将对象从一台计算机或一个应用程序域传递到另一台计算机或另一个应用程序域。 

      在二进制的序列化过程中,对象的公共字段和私有字段以及类的名称(包括包含该类的程序集)都被转换为字节流,然后写入数据流。二进制序列化生成的文件用文本文档打开之后显示的是乱码,也就是说不能直接读取。在以后反序列化该对象时,创建原始对象的精确复本。

   2   XML 序列化仅序列化公共属性和字段,且不保留类型保真度。当希望提供或使用数据而不限制使用该数据的应用程序时,这很有用。由于 XML 是一个开放式标准,因此,对于通过 Web 共享数据,它是一个有吸引力的选择。SOAP 同样是一个开放式标准,这使它也成为一个颇具吸引力的选择。

     XML序列化仅将对象的公共字段和属性值序列化为xml流,而不转换方法、索引器、私有字段或只读属性(只读集合除外),xml序列化不包括类型信息,即不能保证序列化后的对象在被反序列化时变为同一类型的对象。xml生成的文件结构是标准的xml文件结构。



     有关类的定义及使用:

  

  1将字符读取与写入文件:
读入一行,或几行: StreamReader 字符流读取类
            StreamReader sreader= new StreamReader(string path ,Encoding encoding );
            path为文件路径,encoding为编码格式,系统默认Unicode编码或指定编码。指定Encoding.default为文件默认的ANSI编码(中文为gb2312,日文为其他),
            还可指定为Encoding.GetEncoding("gb2312")
            例子:
          
            sreader .ReadLine (); //从当前指针位置开始,读取时,指针移向下一行,存在数据就返回,不存在就返回null,

             sreader .ReadToEnd ();//从当前指针位置开始读取数据,直到结束为止。

            例子:

            StreamReader sr = new StreamReader(@"1.txt", Encoding.Default);

            string s = string.Empty;
            while ((s = sr.ReadLine()) != null)
            {
                Console.WriteLine(s);


            }

            Console.WriteLine(sr.CurrentEncoding.EncodingName);

   写入一行:StreamWriter  文件流写入类

            StreamWriter sw = new StreamWriter( string path ,bool append , Encoding encoding);
            sw.WriteLine(对象);
            例子:
             StreamWriter sw = new StreamWriter("3.txt", false);
            sw.WriteLine("kkk");
            sw.Flush(); //有缓存,需要清空
            Console.WriteLine(sw.Encoding.EncodingName);
   读取或写入全部行或全部文本: File   文件的读取与写入类
                    string [] lines= File .ReadAllLines ( string Path ,Encoding  encoding);

                   string s=    File .ReadAllText (string Path ,Encoding  encoding);
                     File .WriteAllLines (string Path ,string [] contents); 
                      File .WriteAllText (string Path ,string content);
       
2字节,二进制数的读写(音频,图片等)

        常用于文件的拷贝,加密

   拷贝:         FileStream fs = new FileStream(@"1.avi", FileMode.Open, FileAccess.Read);
            FileStream fs1 = new FileStream(@"2.avi", FileMode.Create, FileAccess.Write);
            using (fs)
            {
                using (fs1)      当需要访问硬盘资源时,使用完后要释放,调用Dispose()方法,或用using来释放
              
                    byte[] bs = new byte[1024 * 1024];
                    int count = 0;
                    while ((count = fs.Read(bs, 0, bs.Length)) != 0)
                    {
                        fs1.Write(bs, 0, count);
                    }
                }
            } 



   加密:         FileStream fs = new FileStream(@"1.avi", FileMode.Open, FileAccess.Read);
            FileStream fs1 = new FileStream(@"2.avi", FileMode.Create, FileAccess.Write);
            using (fs)
            {
                using (fs1)
                {
                    byte[] bs = new byte[1024 * 1024];
                    int count = 0;
                    while ((count = fs.Read(bs, 0, bs.Length)) != 0)
                    {

                        //得到了一个字节数组,若直接写入新文件,表示复制,
                        // 如果要加密,需要一个密钥,可以将其设为1,在每个字节上加上数字1
                        for (int i = 0; i < bs.Length; i++)
                        {

                            bs[i]++;

                        }

                        //将bs中的数据写入新文件中
                        fs1.Write(bs, 0, count);
                    }
                }
 

3 对象,数组等 的保存与传输:序列化 

   二进制序列化语法,类前加上标记 [Serializable]

  用BinaryFormatter类,创建实例,调用Serialize和Deserialize方法进行序列化和反序列化
            


 

   二进制序列化:             List<Person> ps = new List<Person>();
                    ps.Add(new Person());



                    FileStream fs = new FileStream(@"D:\序列化", FileMode.Create, FileAccess.Write);
                    using (fs)
                    {
                        BinaryFormatter bf = new BinaryFormatter();
                        bf.Serialize(fs, ps);
                    }





            }
            }


            [Serializable]
            class Person
            {
                public Person()
                {

                }



            } 

      反序列化:  List<Person> ps;                    
            FileStream fs = new FileStream(@"D:\反序列化", FileMode.Open, FileAccess.Read);                  
            using (fs)                   
            {   :                  
                BinaryFormatter bf = new BinaryFormatter();                 
                ps = (List<Person>)bf.Deserialize(fs);                   
            }             
        }          
    }            
    [Serializable]            
    class Person          
    {              
        public Person()                
        {              
        }          
    }