【c#基础】文件读写操作

本章主要记录 FileStream 和 StreamRead 在需要频繁读写时,如何联合使用的场景。
备注:任何性能提升都几乎完全来自并行处理而不是异步处理。 异步的优点在于它不会占用多个线程,也不会占用用户界面线程。
【参考文章】
https://learn.microsoft.com/zh-cn/dotnet/api/system.io?view=net-7.0
https://blog.csdn.net/awangdea99/article/details/100694544
https://blog.csdn.net/zhangguoliang0210/article/details/4138428

FileStream 基本操作

为文件提供 Stream,既支持同步读写操作,也支持异步读写操作。主要是以字节为单位。

以下演示了 FileStream 的一些常用操作:

using System;
using System.IO;
using System.Text;

class Test
{
    public 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\nThe following is a subset of characters:\r\n");

            for (int i=1;i < 120;i++)
            {
                AddText(fs, Convert.ToChar(i).ToString());
            }
        }

        //打开文件并读取至输出窗口
        using (FileStream fs = File.OpenRead(path))
        {
            byte[] b = new byte[1024];
            UTF8Encoding temp = new UTF8Encoding(true);
            int readLen;
            //readLen:读入缓冲区中的总字节数。 如果字节数当前不可用,则总字节数可能小于所请求的字节数;如果已到达流结尾,则为零。
            //b:当此方法返回时,包含指定的字节数组,此数组中 offset 和 (offset + count - 1) 之间的值被从当前源中读取的字节所替换。
            while ((readLen = fs.Read(b,0,b.Length)) > 0)
            {
                Console.WriteLine(temp.GetString(b,0,readLen));
            }
        }
    }

    private static void AddText(FileStream fs, string value)
    {
        byte[] info = new UTF8Encoding(true).GetBytes(value);
        //将字节块写入文件流。info:要写入该流的数据的缓冲区;0:从0开始;info.length:最多写入的字节数
        fs.Write(info, 0, info.Length);
    }
}

以下示例演示如何使用两个 FileStream 对象将文件从一个目录异步复制到另一个目录。 FileStream 类是从 Stream 类派生的。 需要注意 Click 控件的 Button 事件处理程序具有 async 修饰符标记,因为它调用异步方法。

using System;
using System.Threading.Tasks;
using System.Windows;
using System.IO;

namespace WpfApplication
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            string StartDirectory = @"c:\Users\exampleuser\start";
            string EndDirectory = @"c:\Users\exampleuser\end";

            foreach (string filename in Directory.EnumerateFiles(StartDirectory))
            {
                using (FileStream SourceStream = File.Open(filename, FileMode.Open))
                {
                    using (FileStream DestinationStream = File.Create(EndDirectory + filename.Substring(filename.LastIndexOf('\\'))))
                    {
                        await SourceStream.CopyToAsync(DestinationStream);
                    }
                }
            }
        }
    }
}

以下演示文件复制操作

        static void Main(string[] args)
        {
            string sourcePath = @"D:\From\source.mp4";//需要被复制的文件的路径
            string targetPath = @"D:\To\target.mp4";//复制到的路径
            using (FileStream fsRead = new FileStream(sourcePath, FileMode.OpenOrCreate, FileAccess.Read))
            {//创建读取文件的流
                using (FileStream fsWrite = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.Write))
                {//创建写入文件的流
                    byte[] buffer = new byte[1024 * 1024 * 2];//缓存设置2MB;
                    while (true)//循环读取
                    {
                        int r = fsRead.Read(buffer, 0, buffer.Length);//读数据
                        if (r == 0)//读不到数据了,跳出循环
                        {
                            break;
                        }
                        fsWrite.Write(buffer, 0, r);//写数据
                    }
                }
            }
            Console.WriteLine("复制完成!");
            Console.ReadKey();
        }

以下示例演示如何以异步方式写入文件。 此代码在 WPF 应用中运行,该应用具有一个名为 UserInput 的 TextBlock 和一个与名为 Button_Click 的 Click 事件处理程序挂钩的按钮。 需要将文件路径更改为计算机上存在的文件。

using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.IO;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            UnicodeEncoding uniencoding = new UnicodeEncoding();
            string filename = @"c:\Users\exampleuser\Documents\userinputlog.txt";

            byte[] result = uniencoding.GetBytes(UserInput.Text);

            using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate))
            {
                SourceStream.Seek(0, SeekOrigin.End);
                await SourceStream.WriteAsync(result, 0, result.Length);
            }
        }
    }
}

StreamRead 和 StreamWrite 基本操作

StreamRead: 实现从字符串进行读取的 TextReader。
StreamWrite: 实现用于将信息写入字符串的 TextWriter。 信息存储在基础 StringBuilder 中。

以下演示如何使用 StreamWriter 对象写入一个文件,该文件列出 C 驱动器上的目录,然后使用 StreamReader 对象读取和显示每个目录名称。 一种很好的做法是在语句中使用这些对象, using 以便正确地释放非托管资源。 using当使用对象的代码已完成时,该语句会自动对 Dispose 该对象调用。 在此示例中使用的构造函数不支持在 Windows 应用商店应用程序中使用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace StreamReadWrite
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the directories currently on the C drive.
            DirectoryInfo[] cDirs = new DirectoryInfo(@"c:\").GetDirectories();

            // Write each directory name to a file.
            using (StreamWriter sw = new StreamWriter("CDriveDirs.txt"))
            {
                foreach (DirectoryInfo dir in cDirs)
                {
                    sw.WriteLine(dir.Name);
                }
            }

            // Read and show each line from the file.
            string line = "";
            using (StreamReader sr = new StreamReader("CDriveDirs.txt"))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }
        }
    }
}

FileStream 和 StreamWrite

以下演示使用指定的编码及默认的缓冲区大小,为指定的流初始化 StreamWriter 类的新实例。

using System;
using System.IO;
using System.Text;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            string fileName = "test.txt";
            string textToAdd = "Example text in file";
            FileStream fs = null;
            try
            {
               fs = new FileStream(fileName, FileMode.CreateNew);
               using (StreamWriter writer = new StreamWriter(fs, Encoding.Default))
                {
                    writer.Write(textToAdd);
                }
            }
            finally
            {
                if (fs != null)
                    fs.Dispose();
            }
        }
    }
}

以下演示写操作,不确定添加lock是否影响性能,望指正。

        
        public async void WriteCommandLog(string fileName, string strData)
        {
            try
            {
                lock (locker) //这里使用lock是为了防止线程之间竞争,造成记录缺失
                {
                    using (FileStream SourceStream = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                    using (StreamWriter writer = new StreamWriter(SourceStream, Encoding.UTF8))
                    {
                        writer.WriteLine(strData);
                    }
                }
            }
            catch(IOException ioEx)
            {
            	MessageBox.Show(ioEx.Message.ToString()); 
            }
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值