1. 程式人生 > 其它 >06.檔案(流)IO

06.檔案(流)IO

驅動器,目錄,檔案,序列化,流,其它

參考文章

1. 驅動器操作

Windows作業系統中,儲存介質統稱為驅動器,硬碟由於可以劃分為多個區域,每一個區域稱為一個驅動器

.NET提供DriveInfo類和 DriveType列舉型,以方便在程式中直接使用驅動器

1.1 驅動器資訊

DriveInfo 類表示單個驅動器資訊

例項屬性

屬性 屬性值型別 描述
driveInfo.Name string 驅動器名(C:\)
driveInfo.DriveFormat string 檔案系統格式
driveInfo.DriveType DriveType 驅動器型別
driveInfo.TotalSize long 總空間(位元組)
driveInfo.TotalFreeSpace long 可用空間(位元組)

靜態方法

方法 返回值型別 描述
DriveInfo.GetDrives() DriveInfo 獲取可用驅動器列表

DriveType列舉,驅動器型別

列舉值 描述 列舉值 描述
DriveType.CDRom 光碟機 DriveType.Network 網路驅動器
DriveType.Fixed 硬碟 DriveType.Removeable 軟盤或U盤

1.2 示例程式碼

示例一:獲取本地所有驅動器資訊

using System;
using System.IO;

namespace io1
{
    class Program
    {
        static void Main(string[] args)
        {
            DriveInfo[] dirves = DriveInfo.GetDrives();
            foreach (var driveInfo in dirves)
            {
                Console.Write("驅動器名(C:\\):" + driveInfo.Name);
                Console.Write("\t檔案系統格式:" + driveInfo.DriveFormat);
                Console.Write("\t驅動器型別:" + driveInfo.DriveType);
                Console.Write("\t總空間(位元組):" + driveInfo.TotalSize);
                Console.Write("\t可用空間(位元組):" + driveInfo.TotalFreeSpace);

                Console.WriteLine();
            }
        }
    }
}

示例二:獲取每個【硬碟】驅動器剩餘空間資訊

using System;
using System.IO;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            DriveInfo[] drivers = DriveInfo.GetDrives();
            foreach (DriveInfo driver in drivers)
            {
                if (driver.DriveType == DriveType.Fixed && driver.DriveFormat == "NTFS")
                {
                    Console.WriteLine("在{0}驅動器剩餘空間{1}位元組", 
                                      driver.Name, driver.TotalFreeSpace);
                }
            }
            Console.ReadLine();
        }
    }
}

2. 目錄操作

Windows作業系統中,目錄又稱資料夾,每個驅動器都有一個根目錄,使用”\”表示,如”C:\”表示C驅動器的根目錄

.NET提供了Directory類和DirectoryInfo類,以方便在程式中直接操作目錄

2.1 Directory類(靜態類)

靜態方法(常用)

方法 返回值型別 描述
Directory.Exists(...) bool 判斷目錄是否存在
Directory.CreateDirectory(...) DirectoryInfo 建立新目錄
Directory.Delete(...) void 刪除目錄【子目錄】
Directory.Move(...) void 移動或重新命名目錄
Directory.GetDirectories(...) string[] 獲得子目錄(路徑目錄)列表
Directory.GetFiles(...) string[] 獲得目錄的檔案(包含路徑和字尾)列表
Directory.GetParent(...) DirectoryInfo 獲取此目錄的父目錄(以\符號為分界點)
Directory.GetDirectoryRoot(...) string 獲取此資料夾的根目錄

程式碼示例

using System;
using System.IO;

namespace io2
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\今日安排";

            if (!Directory.Exists(dir))
            {
                Console.WriteLine("資料夾不存在!");
                return;
            }

            // 獲取目錄下所有子目錄(當前目錄下的目錄,無遞迴)
            Console.WriteLine("\t\t目錄");
            string[] directories = Directory.GetDirectories(dir);
            foreach (var directorie_item in directories)
            {
                Console.WriteLine(directorie_item);
            }

            // 獲取目錄下所有檔案(當前目錄下檔案)
            Console.WriteLine("\t\t檔案");
            string[] files = Directory.GetFiles(dir);
            foreach (var file_item in files)
            {
                Console.WriteLine(file_item);
            }

            // 獲取資料夾建立時間
            Console.WriteLine("\t\t建立時間");
            Console.WriteLine(Directory.GetCreationTime(dir));

            // 獲取資料夾根目錄
            Console.WriteLine("\t\t根目錄");
            Console.WriteLine(Directory.GetDirectoryRoot(dir));

            Console.WriteLine("\t\t父目錄");
            Console.WriteLine(Directory.GetParent(@"X:\今日安排").Name);    // X:\
            Console.WriteLine(Directory.GetParent(@"X:\今日安排\").Name);   // 今日安排

            Console.WriteLine("\t\t移動並重命名目錄(只限當前碟符內操作)");
            Directory.Move(@"X:\今日安排\A", @"X:\B");  // 移動並重命名目錄
            Directory.Move(@"X:\B", @"X:\C"); // 重新命名目錄
            
            Console.WriteLine("\t\t刪除目錄(謹慎操作)");
            Directory.Delete(@"X:\d");  // 刪除空目錄,非空時異常
            Directory.Delete(@"X:\e",true); // 遞迴刪除目錄(包括目錄下子目錄,檔案)
        }
    }
}

2.2 DirectoryInfo類(例項類)

例項屬性(常用)

屬性 屬性值型別 描述
directory.Name string 目錄名
directory.Root DirectoryInfo 根目錄
directory.Parent DirectoryInfo 父目錄
directory.Exists bool 判斷目錄是否存在
directory.FullName string 目錄全路徑

例項方法

方法 返回值型別 描述
directory.Create() void 建立目錄
directory.Delete(...) void 刪除目錄【子目錄】
directory.GetFiles(...) FileInfo[] 獲取目錄下檔案物件(此目錄)
directory.GetDirectories(...) DirectoryInfo[] 獲取目錄下目錄物件(此目錄)
directory.MoveTo(...) void 移動目錄或重新命名

示例程式碼

示例一:獲取目錄基本資訊

using System;
using System.IO;

namespace io2
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\今日安f排";

            DirectoryInfo directory = new DirectoryInfo(dir);
            Console.WriteLine("目錄名:"+directory.Name);
            Console.WriteLine("根目錄:"+directory.Root.Name);
            Console.WriteLine("父目錄:"+directory.Parent.Name);
            Console.WriteLine("判斷目錄是否存在:" + directory.Exists);
            Console.WriteLine("目錄全路徑:"+directory.FullName);
        }
    }
}

示例二:方法操作

using System;
using System.IO;

namespace io2
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\今日安排";

            DirectoryInfo directory = new DirectoryInfo(dir);
            if (directory.Exists)
            {
                directory.Create();
            }

            Console.WriteLine("\t\t目錄下檔案物件");
            foreach (FileInfo file_item in directory.GetFiles())
            {
                Console.WriteLine(file_item.Name);
            }

            Console.WriteLine("\t\t目錄下目錄物件");
            foreach (DirectoryInfo dir_item in directory.GetDirectories())
            {
                Console.WriteLine(dir_item.Name);
            }

            DirectoryInfo info = new DirectoryInfo(@"X:\a");
            info.MoveTo(@"x:\b");
        }
    }
}

3. 檔案操作

檔案的操作主要是分為兩個類,一個是File類,一個是FileInfo類,FileFileInfo類位於System.IO名稱空間,都可以用來實現建立、複製、移動、開啟檔案等操作

3.1 File類(靜態類)

File類是一個檔案的基本操作類,提供用於建立、複製、刪除、移動和開啟檔案的靜態方法,並協助建立 FileStream物件

靜態方法(常用)

方法 返回值型別 描述
File.Exists(...) bool 判斷檔案是否存在
File.Open(...) FileStream 開啟或建立檔案
File.Create(...) FileStream 建立或覆蓋檔案,可以指定緩衝區大小
File.Delete(...) void 刪除檔案
File.Copy(...) void 複製檔案
File.Move(...) void 移動檔案
File.AppendAllText(...) void 新建檔案並新增文字內容
File.ReadAllText(...) string 開啟並讀取文字內容
File.AppendText(...) StreamWriter 開啟或建立檔案並建立寫入物件
File.OpenText(...) StreamReader 開啟或建立檔案並建立讀取物件
File.Replace(...) void 刪除原始檔案,並建立替換檔案的備份

示例程式碼

using System;
using System.IO;

namespace io3
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\今日安排";
            string file = "解壓密碼.txt";

            string file_path = Path.Combine(dir, file);

            if (!File.Exists(file_path))
            {
                // 建立檔案(存在則覆蓋),並返回一個開啟的 FileStream 流物件
                FileStream stream = File.Create(file_path);
                stream.Close();
            }

            // 開啟或建立檔案,返回一個可讀可寫的流物件
            FileStream fileStream1 = File.Open(file_path,FileMode.OpenOrCreate);
            fileStream1.Close();

            // 開啟或建立檔案,返回一個可讀的檔案流物件
            FileStream fileStream2 = File.Open(file_path, FileMode.OpenOrCreate, FileAccess.Read);
            fileStream2.Close();

            // 開啟檔案,並指定模式為讀取模式
            using (FileStream fileStream3 = File.OpenRead(file_path))
            {

            }

            // 新建檔案並新增文字
            File.AppendAllText(file_path,"李白", System.Text.Encoding.UTF8);

            // 開啟並讀取檔案內容
            string text = File.ReadAllText(file_path,System.Text.Encoding.UTF8);
            Console.WriteLine(text);

            // 開啟檔案,並建立一個寫入物件
            using (StreamWriter writer = File.AppendText(file_path))
            {

            }

            // 開啟檔案,並建立一個讀取物件
            using (StreamReader reader = File.OpenText(file_path))
            {

            }

            // 複製檔案,指定新檔案路徑,檔名(若已存在在檔名則異常)
            File.Copy(file_path,Path.Combine(dir,"1.txt"));

            // 刪除檔案,前提是檔案必須存在,且沒有使用此檔案
            File.Delete(file_path);
            File.Delete(Path.Combine(dir, "1.txt"));
        }
    }
}

3.2 FileInfo類(例項類)

例項化FileInfo例項時,若指定檔案不存在,在使用例項屬性時不會異常,但是呼叫例項方法(具有返回值的方法)時會異常

例項屬性(常用)

屬性 屬性值型別 描述
fileinfo.Name string 檔名
fileinfo.DirectoryName string 檔案所在目錄名
fileinfo.Directory DirectoryInfo 檔案所在目錄
fileinfo.Exists bool 檔案是否存在
fileinfo.Extension string 檔案字尾名
fileinfo.FullName string 檔案全名稱
fileinfo.Length long 檔案大小(位元組)
fileinfo.IsReadOnly bool 檔案是否只讀

例項方法(常用),常用的方法和File類中的相同

參考 File 類方法

程式碼示例

示例一:獲取檔案基本資訊

using System;
using System.IO;

namespace io3
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\b";
            string file = "1.txt";

            string file_path = Path.Combine(dir, file);

            FileInfo fileinfo = new FileInfo(file_path);

            Console.WriteLine("檔名”" + fileinfo.Name);
            Console.WriteLine("檔案所在目錄:" + fileinfo.Directory.Name);
            Console.WriteLine("檔案所在目錄名:" + fileinfo.DirectoryName);
            Console.WriteLine("檔案是否存在:" + fileinfo.Exists);
            Console.WriteLine("檔案字尾名:" + fileinfo.Extension);
            Console.WriteLine("檔案全名稱:" + fileinfo.FullName);
            Console.WriteLine("檔案大小(位元組):" + fileinfo.Length);
            Console.WriteLine("檔案是否只讀:" + fileinfo.IsReadOnly);
        }
    }
}

示例二:方法操作

using System;
using System.IO;

namespace io3
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\b";
            string file = "1.txt";

            string file_path = Path.Combine(dir, file);

            FileInfo fileinfo = new FileInfo(file_path);

            // 開啟或建立可讀檔案
            using (FileStream stream = fileinfo.Open(FileMode.OpenOrCreate, FileAccess.Read))
            {

            }

            // 開啟檔案並建立輸入(寫)物件
            using (StreamWriter writer = fileinfo.AppendText())
            {

            }
            
            // 刪除檔案
            // fileinfo.Delete();
        }
    }
}

4. 資料流操作

流包括以下基本操作:

  • 讀取(read):把資料從流傳輸到某種資料結構中,如輸出到字元陣列中
  • 寫入(write):把資料從某種資料結構傳輸到流中,如把位元組陣列中的資料傳輸到流中
  • 定位(seek):在流中查詢或重新定位當前位置

4.1 Stream

一個抽象類,提供位元組流的基本屬性,操作,是各種資料流的基類

屬性

  • CanRead(是否支援讀取)

  • CanSeek(是否支援查詢)

  • CanTimeout(是否可以超時)

  • CanWrite(是否支援寫入)

  • Length(流的長度)

  • Position(獲取或設定當前流中的位置)

  • ReadTimeout(獲取或設定讀取操作的超時時間)

  • WriteTimeout(獲取或設定寫操作的超時時間)

方法

  • BeginRead(開始非同步讀操作)

  • BeginWrite(開始非同步寫操作)

  • Close(關閉當前流)

  • EndRead(結束非同步讀操作)

  • EndWrite(結束非同步寫操作)

  • Flush(清除流的所有緩衝區並把緩衝資料寫入基礎裝置)

  • Read(讀取位元組序列)

  • ReadByte(讀取一個位元組)

  • Seek(設定查詢位置)

  • Write(寫入位元組序列)

  • WriteByte(寫入一個位元組)

4.2 各種檔案流

FileStream

檔案流類FileStream以流的形式讀、寫、開啟、關閉檔案;另外,它還可以用來操作諸如:管道、標準輸入/輸出等其他與檔案相關的作業系統控制代碼

MemoryStream

記憶體流MemoryStream類用來在記憶體中建立流,以暫時保持資料,因此有了它就無須在硬碟上建立臨時檔案;它將資料封裝為無符號的位元組序列,可以直接進行讀、寫、查詢操作

BufferedStream

緩衝流BufferedStream類表示把流先新增到緩衝區,再進行資料的讀/寫操作。緩衝區是儲存區中用來快取資料的位元組塊;使用緩衝區可以減少訪問資料時對作業系統的呼叫次數,增強系統的讀/寫功能

4.3 流讀寫器

  • 流讀取器StreamReader類用來以一種特定的編碼(如:UTF-8)從位元組流中讀取字元
  • 流寫入器StreamWriter類用來以一種特定的編碼(如:UTF-8)向流中寫入字元
try
{
    //保留檔案現有資料,以追加寫入的方式開啟d:\file.txt檔案
    StreamWriter m_SW = new StreamWriter(@"d:\file.txt", true);
    //向檔案寫入新字串,並關閉StreamWriter
    m_SW.WriteLine("Another File Operation Method");
    m_SW.Close();               
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
         }
  StreamWriter類提供了另一種從檔案中讀取資料的方法,下面演示其用法:
try
{
    //以絕對路徑方式構造新的StreamReader物件
    StreamReader m_SR = new StreamReader(@"d:\file.txt");
 
    //用ReadToEnd方法將d:\file.txt中的資料全部讀入到字串m_Data中,並關閉StreamReader
    string m_Data = m_SR.ReadToEnd();
    m_SR.Close();
    Console.WriteLine(m_Data);
}
catch (Exception ex)
{
    Console.WriteLine("There is an IOException");
    Console.WriteLine(ex.Message);
}

5. 序列化操作

5.1 二進位制序列化

需要序列化的類必須支援可序列化

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace io5
{
    class Program
    {
        static void Main(string[] args)
        {
            List<User> list = new List<User>
            {
                new User{ id=1,name="李白" },
                new User{ id=2,name="貂蟬" },
                new User{ id=3,name=null }
            };

            // 二進位制序列化
            list.BinarySerialize();

        }
    }

    [Serializable]//必須新增序列化特性
    public class User
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    // 使用擴充套件方法只是為了好呼叫,沒有其它
    public static class SerializeHelper
    {
        // 二進位制序列化器
        public static void BinarySerialize<T>(this List<T> list)
        {
            //使用二進位制序列化物件
            string fileName = Path.Combine("File", @"BinarySerialize.txt");//檔名稱與路徑
            if (!Directory.Exists("File"))
                Directory.CreateDirectory("File");
            using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
            {
                BinaryFormatter binFormat = new BinaryFormatter();//建立二進位制序列化器
                binFormat.Serialize(fStream, list);
            }
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {
                BinaryFormatter binFormat = new BinaryFormatter();//建立二進位制序列化器
                //使用二進位制反序列化物件
                fStream.Position = 0;//重置流位置
                List<T> pList = (List<T>)binFormat.Deserialize(fStream);//反序列化物件
            }
        }
    }
}

5.2 XML序列化

using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace io5
{
    class Program
    {
        static void Main(string[] args)
        {
            List<User> list = new List<User>
            {
                new User{ id=1,name="李白" },
                new User{ id=2,name="貂蟬" },
                new User{ id=3,name=null }
            };

            // 二進位制序列化
            list.XmlSerialize();
        }
    }
    
    public class User
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    // 使用擴充套件方法只是為了好呼叫,沒有其它
    public static class SerializeHelper
    {

        // XML序列化器
        public static void XmlSerialize<T>(this List<T> list)
        {
            //使用XML序列化物件
            string fileName = Path.Combine("File", @"XmlSerialize.xml");//檔名稱與路徑
            if (!Directory.Exists("File"))
                Directory.CreateDirectory("File");
            using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
            {
                XmlSerializer xmlFormat = new XmlSerializer(typeof(List<T>));//建立XML序列化器,需要指定物件的型別
                xmlFormat.Serialize(fStream, list);
            }
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {
                XmlSerializer xmlFormat = new XmlSerializer(typeof(List<T>));//建立XML序列化器,需要指定物件的型別
                //使用XML反序列化物件
                fStream.Position = 0;//重置流位置
                List<T> pList = pList = (List<T>)xmlFormat.Deserialize(fStream);
            }
        }
    }
}

5.3 JSON序列化

using Newtonsoft.Json;
using System.Collections.Generic;

namespace io5
{
    class Program
    {
        static void Main(string[] args)
        {
            List<User> list = new List<User>
            {
                new User{ id=1,name="李白" },
                new User{ id=2,name="貂蟬" },
                new User{ id=3,name=null }
            };
            string jResult = list.ToJson();
            List<User> list1 = SerializeHelper.ToObject<User>(jResult);
        }
    }
    
    public class User
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    // 使用擴充套件方法只是為了好呼叫,沒有其它
    public static class SerializeHelper
    {
        public static string ToJson<T>(this List<T> obj)
        {
            return JsonConvert.SerializeObject(obj);
        }
        public static List<T> ToObject<T>(string content)
        {
            return JsonConvert.DeserializeObject<List<T>>(content);
        }
    }
}

6. 示例程式碼

6.1 示例一:簡單文字日誌

using System;
using System.IO;

namespace io4
{
    class Program
    {
        static void Main(string[] args)
        {
            Log("李白");
        }
        static void Log(string msg)
        {
            StreamWriter writer = null;

            string file_path = Path.Combine("Log",DateTime.Now.ToString("yyyyMMddHHmmss")+".log");
            try
            {
                // bin 資料夾中建立 Log 資料夾
                if (!Directory.Exists("Log"))
                {
                    Directory.CreateDirectory("Log");
                }
                writer = File.AppendText(file_path);
                writer.WriteLine(msg);
            }
            catch (Exception ex)
            {
                writer.WriteLine(ex.Message);
            }
            finally
            {
                if (writer != null)
                {
                    writer.Flush();
                    writer.Close();
                    writer.Dispose();
                }
            }
        }
    }
}

7. 擴充套件補充

7.1 Path類

using System;
using System.IO;

namespace io4
{
    class Program
    {
        static void Main(string[] args)
        {
            string dir = @"X:\b";
            string file = "1.txt";

            string file_path = Path.Combine(dir,file);

            Console.WriteLine(Path.GetDirectoryName(@"X:\b"));  // X:\
            Console.WriteLine(Path.GetDirectoryName(@"X:\b\")); // X:\b

            Console.WriteLine(Path.GetRandomFileName());    // 返回隨機的檔名(包含字尾)
            Console.WriteLine(Path.GetFileNameWithoutExtension(file_path)); // 返回當前檔案(無後綴)/目錄名

            Console.WriteLine(Path.GetInvalidPathChars());  // 返回在路徑中禁止使用額字元
            Console.WriteLine(Path.GetInvalidFileNameChars());  // 返回在檔名中禁止使用額字元

            Console.WriteLine(Path.Combine(dir,"c",file));  // 合併路徑與檔名,檔名必須在最後一個位
        }
    }
}

7.2 目錄操作

Directory類和DirectoryInfo類區別

兩者可以說絕大多數功能是重複的,只是directoryinfo需要例項化使用,directory為靜態函式,一個是例項類,一個是公用的靜態類

兩者是為不同的使用場景準備的,directoryinfodirectory的函式內部有一些是相同的處理函式,而且某些directoryinfo的函式甚至就直接呼叫了directory函式;如果多次使用某個物件一般使用前者(directoryinfo),如果僅執行某一個操作則使用後者(directory)提供的靜態方法效率更高一些

Directory類獲取父目錄,使用時需要注意,目錄之間以\為分界點

Console.WriteLine(Directory.GetParent(@"X:\今日安排").Name);    // X:\
Console.WriteLine(Directory.GetParent(@"X:\今日安排\").Name);   // 今日安排

DirectoryDirectoryInfo移動目錄,移動操作只能在同一碟符內(window上目錄名不區分大小寫)

Directory.Move(@"X:\今日安排\A", @"X:\B");  // 移動並重命名目錄
Directory.Move(@"X:\b", @"X:\C"); // 重新命名目錄
DirectoryInfo info = new DirectoryInfo(@"X:\a");
info.MoveTo(@"x:\b");	// 重新命名

Directory類刪除目錄,需要注意目錄下是否有子項(目錄,檔案)

Directory.Delete(@"X:\d");  // 刪除空目錄,非空時異常
Directory.Delete(@"X:\e",true); // 遞迴刪除目錄(包括目錄下子目錄,檔案)
DirectoryInfo info = new DirectoryInfo(@"X:\a");
info.Deleve();	// 刪除目錄,有子項時異常
info.Deleve(true);	// 刪除目錄,包括子項

初始化 DirectoryInfo 例項時,傳入的目錄路徑如果不存在也不會異常(推薦先判斷後操作)

說明:使用例項物件屬性時不會發生異常,但是使用例項方法時(具有返回值的方法)目錄不存在會異常

DirectoryInfo directory = new DirectoryInfo("X:\1");	// 如果目錄不存在不會異常
DirectoryInfo directory = new DirectoryInfo("X:\2");

directory.Create();	// 不存在不會異常
var files = directory.GetFiles();	// 不存在異常

7.3 檔案操作

靜態類與例項類使用場景

  • File類和Directory類適合對不同的物件進行單一的處理,此種特殊情況下,靜態方法的呼叫速度比較快,不用進行例項化
  • FileInfo類和DirectoryInfo類適合用於對同一檔案或資料夾進行多種操作的情況,此種情況下,例項化後的物件不需要每次都尋找檔案,可以直接對該檔案進行操作

7.4 XML序列化

補充示例一

using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace io5
{
    class Program
    {
        static void Main(string[] args)
        {
            List<User> list = new List<User>
            {
                new User{ id=1,name="李白" },
                new User{ id=2,name="貂蟬" },
                new User{ id=3,name=null }
            };

            var text = SerializeHelper.ToXml(list);
            var list1 = SerializeHelper.ToObject<List<User>>(text);
            var list2 = SerializeHelper.FileToObject<List<User>>("");
        }
    }
    
    public class User
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    // 使用擴充套件方法只是為了好呼叫,沒有其它
    public static class SerializeHelper
    {
        // XmlSerializer序列化實體為字串
        public static string ToXml<T>(T t) where T : new()
        {
            XmlSerializer xmlSerializer = new XmlSerializer(t.GetType());
            Stream stream = new MemoryStream();
            xmlSerializer.Serialize(stream, t);
            stream.Position = 0;
            StreamReader reader = new StreamReader(stream);
            string text = reader.ReadToEnd();
            return text;
        }

        // 字串XML序列化成實體
        public static T ToObject<T>(string content) where T : new()
        {
            using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)))
            {
                XmlSerializer xmlFormat = new XmlSerializer(typeof(T));
                return (T)xmlFormat.Deserialize(stream);
            }
        }

        // 檔案反序列化成實體
        public static T FileToObject<T>(string fileName) where T : new()
        {
            string CurrentXMLPath = "File";
            fileName = Path.Combine(CurrentXMLPath, @"XmlSerialize.xml");
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {
                XmlSerializer xmlFormat = new XmlSerializer(typeof(T));
                return (T)xmlFormat.Deserialize(fStream);
            }
        }
    }
}

補充示例二


using System;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.Data;
using System.Collections.Generic;

namespace IOSerialize.Serialize
{
    public static class xHelper
    {
        /// <summary>   
        /// 實體轉化為XML   
        /// </summary>   
        public static string ParseToXml<T>(this T model, string fatherNodeName)
        {
            var xmldoc = new XmlDocument();
            var modelNode = xmldoc.CreateElement(fatherNodeName);
            xmldoc.AppendChild(modelNode);

            if (model != null)
            {
                foreach (PropertyInfo property in model.GetType().GetProperties())
                {
                    var attribute = xmldoc.CreateElement(property.Name);
                    if (property.GetValue(model, null) != null)
                        attribute.InnerText = property.GetValue(model, null).ToString();
                    //else
                    //    attribute.InnerText = "[Null]";
                    modelNode.AppendChild(attribute);
                }
            }
            return xmldoc.OuterXml;
        }

        /// <summary>
        /// XML轉換為實體,預設 fatherNodeName="body"
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml"></param>
        /// <param name="fatherNodeName"></param>
        /// <returns></returns>
        public static T ParseToModel<T>(this string xml, string fatherNodeName = "body") where T : class ,new()
        {
            if (string.IsNullOrEmpty(xml))
                return default(T);
            var xmldoc = new XmlDocument();
            xmldoc.LoadXml(xml);
            T model = new T();
            var attributes = xmldoc.SelectSingleNode(fatherNodeName).ChildNodes;
            foreach (XmlNode node in attributes)
            {
                foreach (var property in model.GetType().GetProperties().Where(property => node.Name == property.Name))
                {
                    if (!string.IsNullOrEmpty(node.InnerText))
                    {
                        property.SetValue(model,
                                          property.PropertyType == typeof(Guid)
                                              ? new Guid(node.InnerText)
                                              : Convert.ChangeType(node.InnerText, property.PropertyType));
                    }
                    else
                    {
                        property.SetValue(model, null);
                    }
                }
            }
            return model;
        }

        /// <summary>
        /// XML轉實體
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml"></param>
        /// <param name="headtag"></param>
        /// <returns></returns>
        public static List<T> XmlToObjList<T>(this string xml, string headtag)
            where T : new()
        {

            var list = new List<T>();
            XmlDocument doc = new XmlDocument();
            PropertyInfo[] propinfos = null;
            doc.LoadXml(xml);
            XmlNodeList nodelist = doc.SelectNodes(headtag);
            foreach (XmlNode node in nodelist)
            {
                T entity = new T();
                if (propinfos == null)
                {
                    Type objtype = entity.GetType();
                    propinfos = objtype.GetProperties();
                }
                foreach (PropertyInfo propinfo in propinfos)
                {
                    //實體類欄位首字母變成小寫的  
                    string name = propinfo.Name.Substring(0, 1) + propinfo.Name.Substring(1, propinfo.Name.Length - 1);
                    XmlNode cnode = node.SelectSingleNode(name);
                    string v = cnode.InnerText;
                    if (v != null)
                        propinfo.SetValue(entity, Convert.ChangeType(v, propinfo.PropertyType), null);
                }
                list.Add(entity);

            }
            return list;
        }
    }
}

7.5 Linq to xml示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace IOSerialize.Serialize
{
    /// <summary>
    /// Linq to xml示例
    /// </summary>
    public class LinqToXml
    {
        /// <summary>
        /// 建立XML檔案
        /// </summary>
        /// <param name="xmlPath"></param>
        private static void CreateXmlFile(string xmlPath)
        {
            try
            {
                //定義一個XDocument結構
                XDocument myXDoc = new XDocument(
                   new XElement("Users",
                       new XElement("User", new XAttribute("ID", "111111"),
                           new XElement("name", "EricSun"),
                           new XElement("password", "123456"),
                           new XElement("description", "Hello I'm from Dalian")),
                       new XElement("User", new XAttribute("ID", "222222"),
                           new XElement("name", "Ray"),
                           new XElement("password", "654321"),
                           new XElement("description", "Hello I'm from Jilin"))));
                //儲存此結構(即:我們預期的xml檔案)
                myXDoc.Save(xmlPath);

                string aa = myXDoc.ToString();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        /// <summary>
        /// 遍歷xml資訊
        /// </summary>
        /// <param name="xmlPath"></param>
        private static void GetXmlNodeInformation(string xmlPath)
        {
            try
            {
                //定義並從xml檔案中載入節點(根節點)
                XElement rootNode = XElement.Load(xmlPath);
                //XElement rootNode2 = XElement.Parse(xmlPath);

                //查詢語句: 獲得根節點下name子節點(此時的子節點可以跨層次:孫節點、重孫節點......)
                IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("name")
                                                    select target;
                foreach (XElement node in targetNodes)
                {
                    Console.WriteLine("name = {0}", node.Value);
                }

                //查詢語句: 獲取ID屬性值等於"111111"並且函式子節點的所有User節點(並列條件用"&&"符號連線)
                IEnumerable<XElement> myTargetNodes = from myTarget in rootNode.Descendants("User")
                                                      where myTarget.Attribute("ID").Value.Equals("111111")
                                                            && myTarget.HasElements
                                                      select myTarget;
                foreach (XElement node in myTargetNodes)
                {
                    Console.WriteLine("name = {0}", node.Element("name").Value);
                    Console.WriteLine("password = {0}", node.Element("password").Value);
                    Console.WriteLine("description = {0}", node.Element("description").Value);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }


        public static void ModifyXmlNodeInformation(string xmlPath)
        {
            try
            {
                //定義並從xml檔案中載入節點(根節點)
                XElement rootNode = XElement.Load(xmlPath);
                //查詢語句: 獲取ID屬性值等於"222222"或者等於"777777"的所有User節點(或條件用"||"符號連線)
                IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("User")
                                                    where target.Attribute("ID").Value == "222222"
                                                          || target.Attribute("ID").Value.Equals("777777")
                                                    select target;
                //遍歷所獲得的目標節點(集合)
                foreach (XElement node in targetNodes)
                {
                    //將description節點的InnerText設定為"Hello, I'm from USA."
                    node.Element("description").SetValue("Hello, I'm from USA.");
                }
                //儲存對xml的更改操作
                rootNode.Save(xmlPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        private static void AddXmlNodeInformation(string xmlPath)
        {
            try
            {
                //定義並從xml檔案中載入節點(根節點)
                XElement rootNode = XElement.Load(xmlPath);
                //定義一個新節點
                XElement newNode = new XElement("User", new XAttribute("ID", "999999"),
                                                            new XElement("name", "Rose"),
                                                            new XElement("password", "456123"),
                                                            new XElement("description", "Hello, I'm from UK."));
                //將此新節點新增到根節點下
                rootNode.Add(newNode);
                //Add 在 XContainer 的子內容的末尾新增內容。
                //AddFirst 在 XContainer 的子內容的開頭新增內容。
                //AddAfterSelf 在 XNode 後面新增內容。
                //AddBeforeSelf 在 XNode 前面新增內容。
                //儲存對xml的更改操作
                rootNode.Save(xmlPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        private static void DeleteXmlNodeInformation(string xmlPath)
        {
            try
            {
                //定義並從xml檔案中載入節點(根節點)
                XElement rootNode = XElement.Load(xmlPath);
                //查詢語句: 獲取ID屬性值等於"999999"的所有User節點
                IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("User")
                                                    where target.Attribute("ID").Value.Equals("999999")
                                                    select target;

                //將獲得的節點集合中的每一個節點依次從它相應的父節點中刪除
                targetNodes.Remove();
                //儲存對xml的更改操作
                rootNode.Save(xmlPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

    }
}

7.6 其它補充

(推薦方法)組合目錄與檔案路徑,路徑末尾有無 \ 效果一樣

Console.WriteLine(Path.Combine(@"X:\今日安排", "A..txt"));
Console.WriteLine(Path.Combine(@"X:\今日安排\", "A..txt"));

獲取專案根目錄方法集合

控制檯應用程式

// 取得或設定當前工作目錄的完整限定路徑
Environment.CurrentDirectory

// 獲取基目錄,它由程式集衝突解決程式用來探測程式集
AppDomain.CurrentDomain.BaseDirectory

Web應用程式

// 獲取承載在當前應用程式域中的應用程式的應用程式目錄的物理驅動器路徑
HttpRuntime.AppDomainAppPath.ToString();

// 返回與Web伺服器上的指定的虛擬路徑相對的物理檔案路徑
Server.MapPath("") / Server.MapPath("~/");

// 獲取伺服器上ASP.NET應用程式的虛擬應用程式根目錄
Request.ApplicationPath;

WinForm應用程式

// 獲取或設定當前工作目錄的完全限定路徑
Environment.CurrentDirectory.ToString();

// 獲取啟動了應用程式的可執行檔案的路徑,不包括可執行檔案的名稱
Application.StartupPath.ToString();

// 獲取應用程式的當前工作目錄
Directory.GetCurrentDirectory();

// 獲取基目錄,它由程式集衝突解決程式用來探測程式集
AppDomain.CurrentDomain.BaseDirectory;

// 獲取或設定包含該應用程式的目錄的名稱
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
到達勝利之前無法回頭!