黑马程序员-.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培训、期待与您交流! -------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值