C#回顧 – 1.IO文件操作


1.文件操作:File

(1)void AppendAllText(string path, string contents)

(2)bool Exists(string path)

(3)string[] ReadAllLines(string path),讀取文本文件到字符串數組中

(4)string ReadAllText(string path),讀取文本文件到字符串中

(5)void WriteAllText(string path, string contents),將文本contents保存到文件path中,會覆蓋舊內容。

(6)WriteAllLines(string path,string[] contents),將字符串數組逐行保存到文件path中,會覆蓋舊內容

2.目錄操作(文件夾操作):Directory

(1)void Delete(string path, bool recursive) ,刪除目錄

(2)bool Exists(string path)

(3)CreateDirectory,創建文件夾

(4)string[] GetDirectories(string path),得到一個目錄下的子目錄

(5)string[] GetDirectories(string path, string searchPattern, SearchOption searchOption) ,通配符查找目錄下的子目錄

(6)static string[] GetFiles(string path) ,得到一個目錄下的文件

(7)string[] GetFiles(string path, string searchPattern, SearchOption searchOption) ,通配符查找目錄下的文件

(8)DirectoryInfo GetParent(string path) ,得到目錄的父目錄

3.Path 類常用靜態方法

(1)string ChangeExtension(string path, string extension),修改文件的后綴

(2)tring Combine(string path1, string path2) ,將兩個路徑合成一個路徑

(3)string GetDirectoryName(string path) ,得到文件的路徑名

(4)string GetExtension(string path) ,得到文件的擴展名

(5)string GetFileName(string path) ,得到文件路徑的文件名部分

(6)string GetFileNameWithoutExtension(string path),得到去除擴展名的文件名

(7)string GetFullPath(string path) ,得到文件的全路徑

(8)string GetTempFileName() ,得到一個唯一的臨時文件名(*)

(9)string GetTempPath()

(10)Assembly.GetExecutingAssembly(),得到當前exe的絕對路徑

練習讀取和File同目錄下的mm.txt文檔內容(讀取配置的時候經常用到)

4.文件流

(1)FileStream.Read ( ),從流中讀取字節塊並將該數據寫入給定緩沖區中

(2)練習:文件加密(每一位用255-r)。加密就是解密,解密就是加密

5.如何在程序中訪問Access寫相對路徑——(*了解)

(1)OleDbConnection的連接字符串

(2)在WinForm中如果不修改DataDirectory,則運行時修改的是exe同文件夾下的mdb,而開發人員看的是項目中的mdb

6.文件流高級

(1)文件流的FlushCloseDispose。緩沖區

(2)更方便的用法:File.OpenReadFile.OpenWrite,內部還是new。

(3)Stream類是FileStream類的父類,有MemoryStream(內存流)、GZipStream (壓縮解壓流)、CryptoStream (加密流), GZipStream 、 CryptoStream 是裝飾者模式的應用。盡量只操作父類Stream。

    6.3.1 GZipStream壓縮

    6.3.2 GZipStream解壓

 

1、文件操作:File

文本文件編碼,文本文件有不同的存儲方式,將字符串以什么樣的形式保存為二進制,這個就是編碼,UTF-8、ASCII、Unicode等,如果出現亂碼一般就是編碼的問題,文本文件相關的函數一般都有一個Encoding類型的參數,

取得編碼的方式:Encoding.Default、Encoding.UTF8、Encoding.GetEncoding("GBK")。以什么編碼存就以什么編碼取就不會亂碼

File類的常用靜態方法:
(1)void AppendAllText(string path, string contents),

將文本contents附加到文件path中
(2)bool Exists(string path)

判斷文件path是否存在

static void Main(string[] args)
        {
            string s = "asasas";
            if (File.Exists("H:/1.txt"))
            {
                Console.WriteLine("文件已經存在,是否覆蓋?(Y/N)");
                string o = Console.ReadLine();
                if (o=="y")
                {
                    File.WriteAllText("H:/1.txt",s);
                }
            }
        }
 

 

imageimage

結果

image
(3)string[] ReadAllLines(string path)

讀取文本文件到字符串數組中

string[] s = File.ReadAllLines("H:/1.txt");
            foreach (var mw in s)
            {
                Console.WriteLine(mw);
            }
 
            Console.ReadKey();

imageimage


(4)string ReadAllText(string path)

讀取文本文件到字符串中
(5)void WriteAllText(string path, string contents)

將文本contents保存到文件path中,會覆蓋舊內容。
(6)WriteAllLines(string path,string[] contents),

將字符串數組逐行保存到文件path中,會覆蓋舊內容。

 

2、目錄操作(文件夾操作):Directory

Directory類的常用靜態方法:(目錄就是文件夾)
(1)void Delete(string path, bool recursive)    

刪除目錄, recursive表示是否遞歸刪除,如果recursive為false則只能刪除空目錄

Directory.Delete("H:/test1",true);
 

(2)bool Exists(string path)

判斷目錄是否存在
(3)CreateDirectory

創建文件夾

問題:需要在H:/temp1/a.txt寫入字符串aabbccdd.

image

解析:沒有目錄。

string s = "aabbccdd";
Directory.CreateDirectory(@"H:\temp1");
File.WriteAllText("H:/temp1/a.txt",s);
 

(4)string[] GetDirectories(string path)

得到一個目錄下的子目錄

string[] files = Directory.GetDirectories(@"c:\");
foreach (string file in files)
{
    Console.WriteLine(file);
}
Console.ReadKey();
 

image


(5)string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)   

通配符查找目錄下的子目錄


(6)static string[] GetFiles(string path) 

得到一個目錄下的文件

string[] files = Directory.GetFiles(@"c:\");
foreach (string file in files)
{
    Console.WriteLine(file);
}
Console.ReadKey();
 

image


(7)string[] GetFiles(string path, string searchPattern, SearchOption searchOption) 

 通配符查找目錄下的文件

string[] strings = Directory.GetFiles(@"G:\電影\", "*.rmvb", SearchOption.AllDirectories);
foreach (string s in strings)
{
    Console.WriteLine(s);
}
Console.ReadKey();
 

image


(8)DirectoryInfo GetParent(string path) 

得到目錄的父目錄

3.Path類常用靜態方法

(1)string ChangeExtension(string path, string extension) (*)

    修改文件的后綴,“修改”支持字符串層面的,沒有真的給文件改名

    string s = Path.ChangeExtension(@"C:\temp\F3.png", "jpg")

image

(2)tring Combine(string path1, string path2)
將兩個路徑合成一個路徑,比用+好,可以方便解決是不是加斜線的問題,自動處理路徑分隔符的問題
string s = Path.Combine(@"c:\temp","a.jpg")

image

(3)string GetDirectoryName(string path) (*)
得到文件的路徑名。Path.GetDirectoryName(@"c:\temp\a.jpg")

image

(4)string GetExtension(string path)

得到文件的擴展名,例如用來限制用戶上傳exe的功能

image
(5)string GetFileName(string path)

得到文件路徑的文件名部分

image
(6)string GetFileNameWithoutExtension(string path)

得到去除擴展名的文件名

image
(7)string GetFullPath(string path)

得到文件的全路徑。”.\”當前路徑,”..\”上一級路徑,”..\..\”上一級的上一級

imageimage
(8)string GetTempFileName() 

得到一個唯一的臨時文件名(*)

(9)string GetTempPath()

得到臨時文件夾的路徑(*)
(10)得到當前exe的絕對路徑Assembly.GetExecutingAssembly(),不要用Directory.GetCurrentDirectory(),這個可能會變(使用OpenFileDialog或者SetCurrentDirectory())。(*)解決Access文件路徑的問題。

image引用反射

string loc = Assembly.GetExecutingAssembly().Location;
Console.WriteLine(loc);
Console.ReadKey();
 

image

 

練習:讀取和File同目錄下的mm.txt文檔內容(讀取配置的時候經常用到)

image

 

4.文件流

1.拷貝文件的兩種方式:將源文件內容全部讀到內存中,再寫到目標文件中;讀取源文件的1KB內存,寫到目標文件中,再讀取源文件的1KB內存,再寫到目標文件中……。第二種方式就是一種流(Stream)的操作。

2.用File.ReadAllText、File.WriteAllText進行文件讀寫是一次性讀、寫,如果文件非常大會占內存、慢。需要讀一行處理一行的機制,這就是流(Stream)。Stream會只讀取要求的位置、長度的內容。

FileStream.Read ( )方法 :從流中讀取字節塊並將該數據寫入給定緩沖區中。

Stream.Read(Byte[ ], Int32, Int32)

array類型:System.Byte[ ]  此方法返回時包含指定的字節數組,數組中 offset 和 (offset + count - 1) 之間的值被從當前源中讀取的字節替換。

offset類型:System.Int32  array 中的字節偏移量,將在此處開始讀取字節。

count類型:System.Int32  最多讀取的字節數。

3.就像SqlConnection一樣,Stream不會將所有內容一次性讀取到內存中,有一個指針,指針指到哪里才能讀、寫到哪里

using (FileStream a = new FileStream(@"h:\1111111.7z", FileMode.Create))
{
    using (FileStream fs = new FileStream(@"h:\boce1.7z", FileMode.Open))
    {
        byte[] bytes = new byte[1024];
        int readLength;//實際讀出來的長度
        while ((readLength = fs.Read(bytes, 0, bytes.Length)) > 0)
        {
            a.Write(bytes, 0, readLength);
        }
    }
}
 


image

4.流有很多種類,文件流是其中一種。FileStream類new FileStream(“c:/a.txt”, filemode, fileaccess)后兩個參數可選值及含義自己看。 FileStream可讀可寫。可以使用File.OpenRead、File.OpenWrite這兩個簡化調用方法。

5.練習:文件加密(每一位用255-r)。加密就是解密,解密就是加密。

imageimage

imageimage 1112.7z又可以打開了

private void button1_Click(object sender, EventArgs e)
{
    using (FileStream input = new FileStream(textBox1.Text, FileMode.Open))
    {
        using (FileStream output = new FileStream(textBox2.Text, FileMode.Create))
        {
            byte[] bytes = new byte[1024 * 1024]; //1M
            int readLength;
            while ((readLength = input.Read(bytes, 0, bytes.Length)) > 0)
            {
                  for (int i = 0; i < readLength; i++) { bytes[i] = (byte)(255 - bytes[i]); }
                output.Write(bytes,0,bytes.Length);
            }
        }
    }
}
 

 

6.byte[]是任何數據的最根本表示形式,任何數據最終都是二進制。

7.Write用於向當前位置寫入若干字節,Read用戶讀取若干字節。(*)每次Read、Write指針都會自動后移。

 

5.如何在程序中訪問Access寫相對路徑——(*了解)

1、OleDbConnection的連接字符串必須是絕對路徑,ADO.Net提供了一個“特殊字符串” DataDirectory表示“數據庫文件夾”,如果是Winform程序DataDirectory表示當前運行的exe的文件夾,對於ASP.Net程序DataDirectory表示當前項目的App_data文件夾。

image

2、在WinForm中如果不修改DataDirectory,則運行時修改的是exe同文件夾下的mdb,而開發人員看的是項目中的mdb。而正式運行的時候則需要程序操作exe同文件夾下的mdb,因此通過代碼修改DataDirectory。代碼見備注,這個代碼要放到程序最開始運行一次即可。如果是WinForm程序則要放到Main最開始

string dataDir = AppDomain.CurrentDomain.BaseDirectory;
if (dataDir.EndsWith(@"\bin\Debug\")
    || dataDir.EndsWith(@"\bin\Release\"))
{
    dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
    AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
}
 

image

 

6.文件流高級

(1)文件流的Flush、Close、Dispose。緩沖區

                string s = "hello";
                byte[] bytes = Encoding.UTF8.GetBytes(s);
                fs.Write(bytes, 0, bytes.Length);//FileStream會把數據寫入緩沖區
                //fs.Flush();//強制把緩沖區的中數據寫入文件
                fs.Close(); //會把沒寫入緩沖區的數據寫入文件(Flush)再關閉
                //Dispose();//會調用colse(),所以調用stream時用using最保險
 
        

這樣可以,最好還是用using

using (FileStream fs = new FileStream(@"H:\1.txt", FileMode.Create))
{
    string s = "hello";
    byte[] bytes = Encoding.UTF8.GetBytes(s);
    fs.Write(bytes, 0, bytes.Length);//FileStream會把數據寫入緩沖區
    //fs.Flush();//強制把緩沖區的中數據寫入文件
    //fs.Close(); //會把沒寫入緩沖區的數據寫入文件(Flush)再關閉
    //Dispose();//會調用colse(),所以調用stream時用using最保險
}
 

(2)更方便的用法:File.OpenRead,File.OpenWrite,內部還是new。

            FileStream ds = File.OpenRead(@"H:\1.txt");//FileMode.Open
          FileStream ds = File.OpenWrite(@"H:\1.txt");//FileMode.Create
 
        

(3)Stream類是FileStream類的父類,有MemoryStream(內存流)、GZipStream (壓縮解壓流)、CryptoStream (加密流), GZipStream 、 CryptoStream 是裝飾者模式的應用。盡量只操作父類Stream。

6.3.1  壓縮

string str = "親,你好嗎?親,你好嗎?親,你好嗎?親,你好嗎?";
for (int i = 0; i < 20; i++)
{
    str += str;
}
using (FileStream fs = File.OpenWrite(@"h:\2.txt"))
{
    byte[] tBytes = Encoding.UTF8.GetBytes(str);
    fs.Write(tBytes, 0, tBytes.Length);
}
 

image

image

點擊壓縮后,

string str = "親,你好嗎?親,你好嗎?親,你好嗎?親,你好嗎?";
for (int i = 0; i < 20; i++)
{
    str += str;
}
using (FileStream fs = File.OpenWrite(@"h:\2.txt"))
{
    //CompressionMode.Compress 壓縮
    using (GZipStream zip = new GZipStream(fs,CompressionMode.Compress))
    {
    byte[] tBytes = Encoding.UTF8.GetBytes(str);
    zip.Write(tBytes, 0, tBytes.Length);
    }
}
 

image

6.3.2 解壓縮

using (FileStream fs = File.OpenRead(@"h:\2.txt"))
{
    using (GZipStream zip =new GZipStream(fs,CompressionMode.Decompress))
    {
        using (FileStream outstream = File.OpenWrite(@"h:\2unzip.txt"))
        {
            int byteaRead;
            byte[] bytes=new byte[1024];
            while ((byteaRead = zip.Read(bytes,0,bytes.Length))>0)
            {
                outstream.Write(bytes,0,byteaRead);
            }
        }
    }
}
 

 

(4)只讀寫文本,不用每次都寫代碼進行復雜的代碼,編寫自己的MyStreamReader、編寫自己的MyStreamWriter。實現復用。

 

7.StreamReader

和StreamWriter類似, StreamReader簡化了文本類型的流的讀取。

ReadToEnd用於從當前位置一直讀到最后,內容大的話會占內存;每次調用都往下走,不能無意中調用了兩次
ReadLine讀取一行,如果到了末尾,則返回null。

        private void button1_Click(object sender, EventArgs e)
        {
            //StreamReader可以讀文件流,壓縮流,內存流等等
            using (Stream fs = File.OpenRead(@"H:\temp1\a.txt"))
            {
                string s = "";
                //因為StreamReader負責在byte[]和string之間轉換,
                //所以需要指定編碼(Encoding.UTF8)
                using (StreamReader stream = new StreamReader(fs,Encoding.UTF8))
                {
                    //ReadLine讀取一行數據,指針自動下移
                    //while ((s = stream.ReadLine()) != null)
                    //{
                    //    MessageBox.Show(s);
                    //}
                    s = stream.ReadToEnd();
                    MessageBox.Show(s);
                }
            }
        }

 

 

8.StreamWriter

Stream把所有內容當成二進制來看待,如果是文本內容,則需要程序員來處理文本和二進制之間的轉換。

用StreamWriter可以簡化文本類型的Stream的處理
StreamWriter是輔助Stream進行處理的

        private void button2_Click(object sender, EventArgs e)
        {
            using (Stream stream = File.OpenWrite(@"H:\temp1\a.txt"))
            {
                string s = "";

using (StreamWriter writer =new StreamWriter(stream,Encoding.UTF8))

                {
                    writer.WriteLine("Hello");
                    writer.WriteLine("World");
                    writer.WriteLine("!啊");
                }
            }
        }

StreamWriter對Stream進行了包裝,調一下writer.WriteLine背后幫我們做了把字符串轉換為二進制的工作。

 

9.WebClient的流操作

WebClient OpenRead方法打開一個讀取流(ReadLine好像有Bug);OpenWrite方法打開一個寫入流。
案例:使用WebClient分析讀取http服務器上的Excel文件,不用中間文件。
基於流方式進行操作的好處就是不用中間文件,沒有安全性問題、沒有文件沖突問題。
開發復雜一點程序的原則就是步步為營,不要想着一次寫出來,比如這個案例就可以分解為:讀取數據庫、創建Excel、上傳Excel三步,所以先讀取數據庫,然后WriteLine看看數據有沒有被正確的讀出來,ok再開發生成Excel的功能,先生成到FileStream中,成功了再最后完成上傳到FTP的功能。這也是迭代的開發方式
File.ReadAllLines(),Stream、FileStream、StreamWriter之間的關系,如何分析Xls等二進制數據

 

10.對象序列化

對象序列化是將對象(比如Person對象)轉換為二進制數據,反序列化是將二進制數據還原為對象。對象是稍縱即逝的,不僅程序重啟、操作系統重啟會造成對象的消失,就是退出函數范圍等都可能造成對象的消失,序列化/反序列化就是為了保持對象的持久化。就像用DV錄像(序列化)和用播放器播放(反序列化)一樣。
BinaryFormatter類有兩個方法:
void Serialize(Stream stream, object graph)對象graph序列化到stream中
object Deserialize(Stream stream)將對象從stream中反序列化,返回值為反序列化得到的對象
練習:將幾個int、字符串添加到ArrayList中,然后序列化到文件中,再反序列化回來。
不是所有對象都能序列化,只有可序列化的對象才能序列化,在類聲明上添加[Serializable],對象的屬性、字段的類型也必須可序列化。
反序列的項目中必須有同樣的類,否則不能反序列化。


未完待續。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM