黑馬程序員-.NET基礎之文件和I/O流

------- Windows Phone 7手機開發.Net培訓、期待與您交流! -------

 

    至今已是我寫的第十篇技術博文,通過看老楊的視頻與自己在大學裏所學的相結合,寫出這十篇博文還是很輕鬆的,但我從寫技術日記的過程中領悟到,任何知識通過第一次的短期記憶還是很不靠譜的,需要我們中加以思考,並提煉成文,這樣才能形成長期記憶,亦或是檢驗自己到底學到多少的一個標杆。

 

一、文件和流操作概述

文件可以看作是數據的集合,一般保存在磁盤或其他存儲介質上。文件I/O(數據的輸入/輸出)通過流(Stream)來實現;流提供一種向後備存儲寫入字節和從後備存儲讀取字節的方式。對於流有5 種基本的操作:打開、讀取、寫入、改變當前位置、關閉。

2.1磁盤的基本操作

DriveInfo類提供方法和屬性以查詢驅動器信息。使用DriveInfo類可以確定可用的驅動器及其類型;確定驅動器的容量和可用空閒空間等。下面是磁盤的基本操作示例。

using System;
using System.IO;
namespace CSharpPractice.IO
{
    class DriverInfoTest
    {
        static void Main()
        {
            DriveInfo[] allDrives = DriveInfo.GetDrives();
            foreach (DriveInfo d in allDrives)
            {
                Console.WriteLine("驅動器 {0}", d.Name);
                Console.WriteLine("  類型: {0}", d.DriveType);
                if (d.IsReady == true)
                {
                    Console.WriteLine("  卷標: {0}", d.VolumeLabel);
                    Console.WriteLine("  文件系統: {0}", d.DriveFormat);
                    Console.WriteLine("  當前用戶可用空間: {0, 15}字節",d.AvailableFreeSpace);
                    Console.WriteLine("  可用空間:         {0, 15}字節",d.TotalFreeSpace);
                    Console.WriteLine("  磁盤總大小:       {0, 15}字節",d.TotalSize);
                    Console.ReadLine();
                }
            }
        }
    }
}

 

2.2目錄的基本操作

Directory類和DirectoryInfo類提供用於目錄基本操作的方法,包括創建、複製、移動、重命名和刪除目錄;獲取和設置目錄的創建、訪問及寫入的時間戳信息等。
Directory所有方法都是靜態的,調用時需要傳入目錄路徑參數。DirectoryInfo類提供實例方法,需要針對要操作的目錄路徑創建DirectoryInfo類的實例,然後調用相應的實例方法,適用於對目錄路徑執行多次操作。
Directory類的靜態方法可以直接調用,而無需構建對象實例,故適用於對目錄路徑執行一次操作;然而Directory類的靜態方法對所有方法都執行安全檢查,如果需要多次重用某個對象,建議使用DirectoryInfo的相應實例方法。下面是DirectoryInfo類目錄的基本操作

using System;
using System.IO;
namespace CSharpPractice.IO
{
    class DirectoryInfoTest
    {
        // 將源目錄複製到目標目錄.
        static public void CopyDirectory(string SourceDirectory, string TargetDirectory)
        {
            DirectoryInfo source = new DirectoryInfo(SourceDirectory);
            DirectoryInfo target = new DirectoryInfo(TargetDirectory);

            //如果源目錄不存在,返回主程序.
            if (!source.Exists)
                return;
            //如果目標目錄不存在,則創建之.
            if (!target.Exists)
                target.Create();

            //文件複製.
            FileInfo[] sourceFiles = source.GetFiles();
            for (int i = 0; i < sourceFiles.Length; ++i)
                File.Copy(sourceFiles[i].FullName, target.FullName + "\\" + sourceFiles[i].Name, true);

            //目錄複製.
            DirectoryInfo[] sourceDirectories = source.GetDirectories();
            for (int j = 0; j < sourceDirectories.Length; ++j)
                CopyDirectory(sourceDirectories[j].FullName, target.FullName + "\\" + sourceDirectories[j].Name);
        }
        
        static void Main()
        {
            string path = @"c:\MyDir";

            try
            {
                //利用DirectoryInfo類創建、刪除目錄
                // 指定要操作的目錄.
                DirectoryInfo di = new DirectoryInfo(path);
                // 確定目錄是否存在.
                if (di.Exists)
                {
                    Console.WriteLine("目錄{0}已經存在!", path);
                    return;
                }
                // 創建目錄.
                di.Create();
                Console.WriteLine("目錄{0}已經成功創建!", path);
                // 刪除目錄.
                di.Delete();
                Console.WriteLine("\n目錄{0}已經成功刪除!", path);

                //調用子程序,將源目錄SourceDirectory複製到目標目錄TargetDirectory
                string SourceDirectory = @"c:\SrcDir";
                string TargetDirectory = @"c:\TarDir";
                CopyDirectory(SourceDirectory, TargetDirectory);
                Console.WriteLine("\n源目錄{0}所有內容已經成功複製到目標目錄{1}中!", SourceDirectory, TargetDirectory);
            }
            catch (Exception e)
            {
                Console.WriteLine("\n操作失敗: {0}", e.ToString());
            }
            finally { }
            Console.ReadLine();
        }
    }
}

 

2.3文件的基本操作

File類和FileInfo類提供用於文件基本操作的方法,包括創建、複製、移動、重命名和刪除文件;打開文件,讀取文件內容和追加內容到文件;獲取和設置文件的創建、訪問及寫入的時間戳信息等。
File所有方法都是靜態的,調用時需要傳入目錄路徑參數。FileInfo類提供實例方法,需要針對要操作的目錄路徑創建FileInfo類的實例,然後調用相應的實例方法,適用於對目錄路徑執行多次操作。
File類的靜態方法可以直接調用,而無需構建對象實例,故適用於對文件執行一次操作;然而File類的靜態方法對所有方法都執行安全檢查,如果需要多次重用某個對象,建議使用FileInfo的相應實例方法。

using System;
using System.IO;
namespace CSharpPractice.IO
{
    class FileInfoTest
    {
        static void Main()
        {
            //string path = Path.GetTempFileName();
            string path = @"c:\temp\SrcFile.txt";
            FileInfo fi1 = new FileInfo(path);

            if (!fi1.Exists)
            {
                //創建文件以寫入內容.
                using (StreamWriter sw = fi1.CreateText())
                {
                    sw.WriteLine("Hello");
                    sw.WriteLine("And");
                    sw.WriteLine("Welcome");
                }
            }

            //打開文件讀取內容.
            Console.WriteLine("源文件內容爲:");
            using (StreamReader sr = fi1.OpenText())
            {
                string s = "";
                while ((s = sr.ReadLine()) != null) Console.WriteLine(s);
            }

            try
            {
                //string path2 = Path.GetTempFileName();
                string path2 = @"c:\temp\DesFile.txt";
                FileInfo fi2 = new FileInfo(path2);

                //刪除目標文件,確保成功複製.
                fi2.Delete();

                //文件複製.
                fi1.CopyTo(path2);
                Console.WriteLine("源文件 {0} 成功複製至目標文件 {1}.", path, path2);

                //刪除目標文件.
                fi2.Delete();
                Console.WriteLine("目標文件{0} 成功刪除.", path2);

                // 打開已存在的文件,或者創建新文件.
                FileInfo fi = new FileInfo(path);
                // 獲取文件完整路徑.
                DirectoryInfo di = fi.Directory;
                // 獲取文件所在目錄中所有文件和子目錄信息.
                FileSystemInfo[] fsi = di.GetFileSystemInfos();
                Console.WriteLine("\n目錄 '{0}' 包含以下文件和子目錄:", di.FullName);
                // 打印文件所在目錄中所有文件和子目錄信息.
                foreach (FileSystemInfo info in fsi) Console.WriteLine(info.Name);

            }
            catch (Exception e)
            {
                Console.WriteLine("\n操作失敗: {0}", e.ToString());
            }
            finally { }
            Console.ReadLine();
        }
    }
}

 

三、文本文件的讀取和寫入

StreamReader類和 StreamWriter類分別以一種特定的編碼從字節流中讀取字符和向流中寫入字符
StringReader類和 StringWriter類分別實現字符串的讀取和寫入操作

1.StreamReader和StreamWriter

StreamReader類實現一個 TextReader,使其以一種特定的編碼從字節流中讀取字符。StreamReader主要用於讀取標準文本文件的各行信息
StreamWriter類實現一個 TextWriter,使其以一種特定的編碼向流中寫入字符。StreamWriter主要用於寫入標準文本文件信息
下面使用StreamReader類和StreamWriter類讀寫文本文件。

using System;
using System.IO;
namespace CSharpPractice.IO
{
    class StreamReaderWriterTest
    {
        private const string FILE_NAME = @"c:\temp\TestFile.txt";
        public static void Main(String[] args)
        {
            // 創建StreamWriter實例以在文件中添加文本.
            using (StreamWriter sw = new StreamWriter(FILE_NAME))
            {
                // 在文件中添加文本.
                sw.Write("文本文件");
                sw.WriteLine("的寫入/讀取示例:");
                sw.WriteLine("----------------------------------");
                // Arbitrary objects can also be written to the file.
                sw.WriteLine("寫入整數 {0} 或浮點數 {1}", 1, 4.2);
                bool b = false; char grade = 'A'; string s = "Multiple Data Type!";
                sw.WriteLine("寫入Boolean 值、字符、字符串、日期:");
                sw.WriteLine(b);
                sw.WriteLine(grade);
                sw.WriteLine(s);
                sw.Write("當前日期爲: ");
                sw.WriteLine(DateTime.Now);
            }
            try
            {
                // 創建StreamReader實例以從文本文件中讀取內容.
                using (StreamReader sr = new StreamReader(FILE_NAME))
                {
                    String line;
                    // 讀取文本文件每一行的內容,直至文件結束.
                    while ((line = sr.ReadLine()) != null)
                    {
                        Console.WriteLine(line);
                    }
                }
            }
            catch (Exception e)
            {   // 異常處理.
                Console.WriteLine("該文件不能正常讀取,原因如下:");
                Console.WriteLine(e.Message);
            }
            Console.ReadLine();
        }
    }
}


 

2.StringReader和StringWriter

StringReader類實現從字符串進行讀取的 TextReader;StringWriter類實現一個用於將信息寫入字符串的 TextWriter;使用StringReader類和StringWriter類讀寫字符串。

using System;
using System.IO;
namespace CSharpPractice.IO{
    class StringReaderWriterTest
    {
        public static void Main(String[] args)
        {
            string textReaderText = "本段爲第一段內容.\n\n" +
                    "第二段內容從這裏開始.\n\n" +
                    "第三段內容也很簡潔,只是示例而已.\n\n";
            Console.WriteLine("原始文本內容如下:");
            Console.WriteLine("-------------------------------------------\n{0}", textReaderText);
            // 將原始文本textReaderText用一組雙倍間距的句子創建一個連續的段落
            // 每個句子以字符“.”結束
            string aLine, aParagraph = null;
            StringReader strReader = new StringReader(textReaderText);
            while (true)
            {
                aLine = strReader.ReadLine();
                if (aLine != null)
                {
                    aParagraph = aParagraph + aLine + " ";
                }
                else
                {
                    aParagraph = aParagraph + "\n";
                    break;
                }
            }
            Console.WriteLine("修改後的文本(連續的段落aParagraph)內容如下:");
            Console.WriteLine("-------------------------------------------\n{0}", aParagraph);
            // 從連續的段落aParagraph恢復原始文本內容textReaderText.
            int intCharacter;
            char convertedCharacter;
            StringWriter strWriter = new StringWriter();
            strReader = new StringReader(aParagraph);
            while (true)
            {
                intCharacter = strReader.Read();
                // 轉換成character前,檢查字符串是否結束.
                if (intCharacter == -1) break;
                convertedCharacter = Convert.ToChar(intCharacter);
                if (convertedCharacter == '.') //一個句子後加入2個回車換行
                {
                    strWriter.Write(".\n\n");
                    // 忽略句子間的空格.
                    strReader.Read();
                    strReader.Read();
                }
                else
                {
                    strWriter.Write(convertedCharacter);
                }
            }
            Console.WriteLine("\n還原後的原始文本內容textReaderTex:");
            Console.WriteLine("-------------------------------------------\n{0}", strWriter.ToString());
            Console.ReadLine();
        }
    }
}


 

四、二進制文件的讀取和寫入

FileStream類支持通過其 Seek 方法隨機訪問文件;
BinaryReader類和 BinaryWriter類在 Streams 中讀取和寫入編碼的字符串和基元數據類型.

1.FileStream類

FileStream類提供對文件進行打開、讀取、寫入、關閉等操作,既支持同步讀寫操作,也支持異步讀寫操作。FileStream支持使用Seek方法對文件進行隨機訪問,Seek通過字節偏移量將讀取/寫入位置移動到文件中的任意位置,字節偏移量是相對於查找參考點(文件的開始、當前位置或結尾,分別對應於SeekOrigin.Begin、SeekOrigin.Current和SeekOrigin.End)。下面是使用FileStream類對二進制文件進行隨機訪問。

using System;
using System.IO;
using System.Text;
namespace CSharpPractice.IO
{
    class FileStreamTest
    {
        static void Main()
        {
            string path = @"c:\temp\MyTest.txt";

            // 如果文件存在,則刪除之.
            if (File.Exists(path)) File.Delete(path);

            // 創建文件.
            using (FileStream fs = File.Create(path))
            {
                AddText(fs, "This is some text。");
                AddText(fs, "This is some more text,");
                AddText(fs, "\r\nand this is on a new line");
                AddText(fs, "\r\n\r\n以下是字符子集:\r\n");

                for (int i = 32; i < 127; i++)
                {
                    AddText(fs, Convert.ToChar(i).ToString());
                    // 每行10字符.
                    if (i % 10 == 0) AddText(fs, "\r\n");
                }
            }

            // 打開流,讀取並顯示其內容.
            using (FileStream fs = File.OpenRead(path))
            {
                byte[] b = new byte[1024];
                UTF8Encoding temp = new UTF8Encoding(true);
                while (fs.Read(b, 0, b.Length) > 0)
                {
                    Console.WriteLine(temp.GetString(b));
                }
            }

            Console.ReadLine();
        }

        private static void AddText(FileStream fs, string value)
        {
            byte[] info = new UTF8Encoding(true).GetBytes(value);
            fs.Write(info, 0, info.Length);
        }

    }
}


 

2.BinaryReader和BinaryWriter

BinaryReader類用特定的編碼將基元數據類型讀作二進制值,BinaryWriter類以二進制形式將基元類型寫入流,並支持用特定的編碼寫入字符串。下面是使用BinaryWriter類和BinaryReader類讀寫二進制數據文件。

using System;
using System.IO;
namespace CSharpPractice.IO
{
    class BinaryReaderWriterTest
    {
        private const string FILE_NAME = @"c:\temp\Test.data";
        public static void Main(String[] args)
        {
            // 創建一個新的、空的數據文件.
            if (File.Exists(FILE_NAME))
            {
                Console.WriteLine("文件 {0} 已經存在,刪除之!", FILE_NAME);
                File.Delete(FILE_NAME);
            }
            FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew);
            // 創建BinaryWriter.
            BinaryWriter w = new BinaryWriter(fs);
            // 寫數據到新的、空的數據文件中.
            for (int i = 0; i < 11; i++)
            {
                w.Write((int)i);
            }
            w.Close();
            fs.Close();
            // 創建BinaryReader.
            fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read);
            BinaryReader r = new BinaryReader(fs);
            // 數據文件中讀取數據.
            for (int i = 0; i < 11; i++)
            {
                Console.WriteLine(r.ReadInt32());
            }
            r.Close();
            fs.Close();
            Console.ReadLine();
        }
    }
}


 

五、通用I/O流類

BufferedStream 是向另一個 Stream(例如 NetworkStream)添加緩衝的 Stream;CryptoStream 將數據流鏈接到加密轉換;MemoryStream 是一個非緩衝的流,可以在內存中直接訪問它的封裝數據。該流沒有後備存儲,可用作臨時緩衝區;NetworkStream 表示網絡連接上的 Stream。

MemoryStream類

MemoryStream創建其支持存儲區爲內存的流,使用MemoryStream流類:通過將內存用作備份來讀取和寫入數據。

using System;
using System.IO;
using System.Text;
namespace CSharpPractice.IO
{
    class MemoryStreamTest
    {
        static void Main()
        {
            int count;
            byte[] byteArray;
            char[] charArray;
            UnicodeEncoding uniEncoding = new UnicodeEncoding();

            // 創建要寫入的數據(2個字符串).
            byte[] firstString = uniEncoding.GetBytes("常用的ASCII字符包括:");
            char[] chars = new char[127];
            for (int i = 65; i < 127; i++) chars[i] = (char)i;
            byte[] secondString = uniEncoding.GetBytes(chars);

            using (MemoryStream memStream = new MemoryStream(100))
            {   // 將第1個字符串寫入內存流.
                memStream.Write(firstString, 0, firstString.Length);

                // 將第2個字符串一個字節一個字節地寫入內存流.
                count = 0;
                while (count < secondString.Length)
                {
                    memStream.WriteByte(secondString[count++]);
                }

                // 將內存流的有關屬性:
                // “分配給流的字節數、流長度、流當前位置”輸出到控制檯.
                Console.WriteLine(
                                "Capacity = {0}, Length = {1}, Position = {2}\n",
                                memStream.Capacity.ToString(),
                                memStream.Length.ToString(),
                                memStream.Position.ToString());

                // 將當前內存流中的位置設置到內存流的開始.
                memStream.Seek(0, SeekOrigin.Begin);

                // 從內存流中讀取20個字節的內容.
                byteArray = new byte[memStream.Length];
                count = memStream.Read(byteArray, 0, 20);

                // 一個字節一個字節地讀取內存流中剩下的字節.
                while (count < memStream.Length)
                {
                    byteArray[count++] = Convert.ToByte(memStream.ReadByte());
                }
                // 將字節數組轉換爲字符數組,並輸出到控制檯.
                charArray = new char[uniEncoding.GetCharCount(byteArray, 0, count)];
                uniEncoding.GetDecoder().GetChars(byteArray, 0, count, charArray, 0);
                Console.WriteLine(charArray);
                Console.ReadLine();
            }
        }
    }
}


 

------- Windows Phone 7手機開發.Net培訓、期待與您交流! -------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章