知识点:掌握文本文件的读写、 掌握文件和文件夹的基本操作
计算机中存在大量的文件,包括:文本文件、图片、视频、音乐和可执行文件等等。这些文件共同的特点是:都保存在磁盘上,可以长时间的保存用户的数据。对于程序员来说,保存数据的主要方式有:保存在数据库中或保存在文件中。数据库的功能强大,但是操作起来比较复杂,适合保存复杂的数据,对于一些简单的数据,可以直接保存在文件中。
下面我们将学习使用文件来保存数据(也称数据持久化)的方法。
文本文件是计算机中最常见,应用最广的文件之一,在 C#中读写文本文件主要有 5 个步骤:
1)创建文件流
2)创建读取器或写入器
3)进行读取或写入操作
4)关闭读取器或写入器
5)关闭文件流
文件流(FileStream)是 C#中用于文件数据传输的对象,可以将文件数据读取到应用程序中,也可 以将应用程序中的数据输入文件保存。 C#中对文件进行输入和输出的类都保存在命名空间 System.IO 中。 创建文件流的语法:
FileStream fileStream = new FileStream(string filePath,FileMode mode);
FileStream 构造方法的参数:
2.2 文件流写入器
文件流写入器(StreamWriter)负责将数据写入文件流。 创建写入器语法:
StreamWriter writer = new StreamWriter(FileStream fileStream);
创建 StreamWriter 对象,需要将前面创建的文件流对象传入构造方法。
StreamWriter 的主要方法:
要求:在文件操作窗体上,将文件路径输入后,点击【写入文件】按钮,可以将填写的内容写入到文件中。(从无到有,新建一个文本文件)
推荐复习内容:创建Windows应用程序的方法
第一步,新建窗体项目:打开Visual Studio软件后,单击【文件】——【新建】——【项目】,在新建项目对话框中选择【Window 窗体应用(.NET Framework)】,这里使用默认名称【WindowsFormsApp1】,然后单击【确定】。
创建完项目后,在VisualStudio 2017开发环境中会有一个默认的窗体Form1。
第二步,设置窗体属性:鼠标单击窗体后,点击右侧【属性】,我们对窗体的属性进行设置:Name属性设置为FrmFile,Size属性设置为400,400 ,Text属性设置为“文件操作”。
第三步,给窗体添加控件:根据需要,从工具箱里添加控件到窗体上,并设置控件的属性,(这里从上往下,从左往右,介绍用到的控件)
第四步,给【写入文件】按钮添加点击事件:在窗体设计界面,双击【写入文件】按钮,进入该按钮的点击事件方法,编写代码。
private void btnWrite_Click(object sender, EventArgs e)//【写入文件】按钮的点击事件
{
if (txtFilename.Text == "")//判断用户是否txtFilename控件中,输入文件路径
{
MessageBox.Show("请填写文件路径");
return;
}
if (txtContent.Text == "")//判断用户是否在txtContent控件中,输入文件内容
{
MessageBox.Show("请填写文件内容");
return;
}
try
{
//创建文件流,第一个参数文件路径,获取的是txtFilename的Text属性,从第二个参数用的是Create,即创建新文件
FileStream stream = new FileStream(txtFilename.Text, FileMode.Create);//初次使用,需要引入命名空间
//创建写入器
StreamWriter writer = new StreamWriter(stream);
//写入内容
writer.WriteLine(txtContent.Text);
//关闭写入器
writer.Close();
//关闭文件流
stream.Close();
MessageBox.Show("OK");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
代码分析:要注意文件流和写入器关闭的顺序,先关闭写入器,后关闭文件流,顺序颠倒的话会发生异常。
第五步:运行测试:点击菜单栏【启动】,验证效果
1)打开电脑任意一个路径,这里打开D:\shu,作为等一下写入文件的位置。
2)在窗体文件路径里输入文件路径D:\shu\test.txt ,然后再输入框里输入内容,最后点击【写入文件】。
3)回到电脑文件夹里,检验我们的写入是否成功。发现D盘里,新增加了一个test.txt文件,打开文件以后,查看文件内容,和我们在窗体上输入的内容一致。
案例思考:这个案例里,我们从无到有,新建了一个文件文件并设置了内容。如果已经有的文件,我们可以写入吗?结果是怎样?
文件流读取器(StreamReader)负责从文件流中读取数据。 创建读取器的语法:
StreamReader reader = new StreamReader(FileStream stream,Encoding encoding);
构造方法的第二个参数是字符编码,常用的字符编码有: Encoding.Default 系统默认编码 、Encoding.UTF8 、 Encoding.UTF7 、Encoding.ASCII , 也可以使用 Encoding.GetEncoding("编码名称")获得其他编码。
读取器的主要方法:
要求:在文件操作窗体上,将文件路径输入后,点击【读取文件】按钮,可以将文件内容读取并显示在窗体下面的输入框里。
操作步骤:给【读取文件】按钮添加点击事件:在窗体设计界面,双击【读取文件】按钮,进入该按钮的点击事件方法,编写代码。
private void btnRead_Click(object sender, EventArgs e)//【读取文件】按钮的点击事件
{
if (txtFilename.Text == "")//判断用户是否输入文件路径
{
MessageBox.Show("请填写文件路径");
return;
}
try
{
FileStream stream = new FileStream(txtFilename.Text, FileMode.Open);//创建文件流,第二个参数用的是Open,即打开文件
StreamReader reader = new StreamReader(stream, Encoding.UTF8);//创建读取器,第一个参数是文件流对象,第二个参数指明字符编码用UTF8(C#默认支持的是 UTF8 编码)
txtContent.Text = reader.ReadToEnd();//将读取器读取到的内容,赋值给txtContent控件的Text属性
reader.Close();//关闭读取器
stream.Close();//关闭文件流
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
运行测试:
System.IO 命名空间中还提供了 File 类和 Directory 类,对文件和目录进行操作。
类 | 方法名 | 说明 |
File 类 |
Exists(string filePath)
|
返回文件是否存在
|
Copy(string source,string destination)
|
复制原文件到目标文件
|
|
Move(string source,string destination)
|
移动原文件到目标文件
|
|
Delete(string path)
|
删除文件
|
|
Directory 类 |
Exists(string filePath)
|
返回目录是否存在
|
Move(string source,string destination)
|
移动目录到目标位置
|
|
Delete(string path,bool recursive)
|
删除目录,
recursive
为
true
时删除所有子目录内容
|
要求:在文件操作窗体上,输入原文件路径和目标文件路径后,点击【复制文件到路径:】按钮,可以将文件复制到目标位置。
操作步骤:给【复制文件到路径:】按钮添加点击事件:在窗体设计界面,双击【复制文件到路径:】按钮,进入该按钮的点击事件方法,编写代码。
private void btnCopy_Click(object sender, EventArgs e)//【复制文件到路径:】按钮的点击事件
{
if (!File.Exists(txtFilename.Text))
{
MessageBox.Show("文件不存在");
return;
}
if (txtTarget.Text == "")
{
MessageBox.Show("请填写复制目标文件路径");
return;
}
try
{
File.Copy(txtFilename.Text, txtTarget.Text);//File.Copy()方法,复制源文件到目标文件
MessageBox.Show("OK");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
运行测试:
打开目标文件路径,发现已经完成文件的复制。
要求:在文件操作窗体上,输入原文件路径后,点击【删除文件】按钮,将删除指定文件。
操作步骤:给【删除文件】按钮添加点击事件:在窗体设计界面,双击【删除文件】按钮,进入该按钮的点击事件方法,编写代码。
private void btnDelete_Click(object sender, EventArgs e)//【删除文件】按钮的点击事件
{
if (!File.Exists(txtFilename.Text))
{
MessageBox.Show("文件不存在");
return;
}
try
{
File.Delete(txtFilename.Text);
MessageBox.Show("OK");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
使用 File 类和 Directory 类时都不需要实例化,直接通过“类名.方法()”的方式调用方法,这是因为 File 和 Directory 都是静态类,它们内部的方法都是静态方法。
定义静态类的语法: static class 类名{...}
静态类和非静态类的区别是:
静态类
|
非静态类
|
用
static
修饰
|
不用
static
修饰
|
只包含静态成员
|
包含静态成员和非静态成员
|
使用类名调用成员
|
使用对象调用成员
|
不能实例化
|
可以实例化
|
不能包含实例构造方法
|
可以包含实例构造方法
|
静态的属性和方法都是用 static 修饰的,静态成员会在第一次访问该类时初始化,其后会一直占用内存,直到程序退出才会释放。所有该类的实例共用唯一的静态成员,就如所有人类对象共用一个地球。 实例成员在创建类的实例时才初始化,每个该类实例都有不同的实例成员。
推荐复习内容:C#中静态方法和实例化方法(普通方法)的区别及使用
C#除了提供静态类 File 和 Directory 来进行文件和目录操作外,还提供了非静态类 FileInfo 和 DirectoryInfo 来进行文件和目录操作,它们的功能是类似的,区别是:FileInfo 和 DirectoryInfo 类使用时必须实例化。
属性
|
说明 |
Exists
|
bool
类型,该文件是否存在
|
Extension
|
文件扩展名的字符串
|
Name
|
文件名
|
FullName
|
完整路径
|
方法
|
说明 |
CopyTo(string destination)
|
复制到目标文件
|
Delete()
|
删除文件
|
MoveTo(string destination)
|
移动到目标位置
|
关键代码:
FileInfo fileInfo = new FileInfo(@"C:\xray\test.txt");//new一个FileInfo类的对象
if(fileInfo.Exists)
{
fileInfo.CopyTo(@"C:\xray\test_copy.txt");//@符号是用来对字符串进行转义的
}
用法和 File 类似,只是需要实例化,大家注意在定义路径字符串时前加了@符号,该符号是对字符 串进行转义,因为\符号属于特殊符号,在字符串中应该用\\表示,加了@符号就不需要了。
DirectoryInfo 类可以对目录进行复制、删除、移动等操作,用法和 FileInfo 类似。 我们这里主要学习 DirectoryInfo 的两个重要方法:
综合运用前面学习的文件和目录操作,开发一个文件资源管理器。文件资源管理器的功能包括:
盘符和目录使用 TreeView 控件显示,初始显示 C 盘,点击某个目录能动态加载下面的子目录。这里我们需要使用 DirectoryInfo 的 GetDirectories()方法获取目录的所有子目录。
点击目录后,能够将目录中所有的文件信息填充到右边的 ListView 中。
第一步,新建窗体项目:打开Visual Studio软件后,单击【文件】——【新建】——【项目】,在新建项目对话框中选择【Window 窗体应用(.NET Framework)】,这里使用默认名称【WindowsFormsApp2】,然后单击【确定】。
第二步,设置窗体属性:鼠标单击窗体后,点击右侧【属性】,我们对窗体的属性进行设置:Name属性设置为FrmFileExplorer,Size属性设置为630,410 ,Text属性设置为“文件资源管理器”。
第三步,给窗体添加控件:根据需要,从工具箱里添加控件到窗体上,并设置控件的属性
相关控件使用,推荐阅读:ListView控件、ContextMenuStrip控件和TreeView控件的使用
第四步,给窗体添加Load事件:双击窗体,进入窗体的Load事件,编写代码,让窗体加载的时候,显示D盘
private void FrmFileExplorer_Load(object sender, EventArgs e)//窗体Load事件
{
tvDirectories.Nodes.Clear();
//初始显示D盘
TreeNode root = tvDirectories.Nodes.Add("D盘");
//保存目录路径到Tag属性中
root.Tag = @"D:\";
}
第五步,声明一个填充ListView的方法:
//填充ListView
private void FillListView(String dirPath)
{
//获得当前目录信息
DirectoryInfo dirInfo = new DirectoryInfo(dirPath);
//获得所有文件
FileInfo[] fileInfos = dirInfo.GetFiles();
lvFiles.Items.Clear();
//填充文件信息到ListView中
foreach (FileInfo fileInfo in fileInfos)
{
ListViewItem item = new ListViewItem(fileInfo.Name);
item.SubItems.Add(Math.Round(fileInfo.Length / 1024.0, 2).ToString());
item.SubItems.Add(fileInfo.Extension);
item.SubItems.Add(fileInfo.FullName);
lvFiles.Items.Add(item);
}
}
第六步,给TreeView控件添加AfterSelect事件:回到窗体的设计界面,选中TreeView控件后,点击【解决方案资源管理器】中的【属性】→点击【事件】→找到【AfterSelect】后,双击,进入AfterSelect事件代码编写。
private void tvDirectories_AfterSelect(object sender, TreeViewEventArgs e)//点击目录事件处理
{
TreeNode node = tvDirectories.SelectedNode;
//获得选择的目录信息
DirectoryInfo dirInfo = new DirectoryInfo(node.Tag.ToString());//需要引入命名空间
//获得所有子目录
DirectoryInfo[] dirs = dirInfo.GetDirectories();
//加载所有子目录
foreach (DirectoryInfo dir in dirs)
{
TreeNode childNode = node.Nodes.Add(dir.Name);
childNode.Tag = dir.FullName;
}
FillListView(node.Tag.ToString());
}
第七步,给ListView控件添加MouseDoubleClick事件:回到窗体的设计界面,选中ListView控件后,点击【解决方案资源管理器】中的【属性】→点击【事件】→找到【MouseDoubleClick】后,双击,进入MouseDoubleClick事件代码编写。
private void lvFiles_MouseDoubleClick(object sender, MouseEventArgs e)//双击ListView事件
{
if (lvFiles.SelectedItems.Count == 0)
{
return;
}
try
{
//获得文件路径
string filePath = lvFiles.SelectedItems[0].SubItems[3].Text;
//启动系统进程,打开文件
System.Diagnostics.Process.Start(filePath);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
第八步,给ContextMenuStrip控件的【删除文件】项,添加Click事件:回到窗体的设计界面,选中ContextMenuStrip控件的【删除文件】项后,双击,进入点击事件,编写代码
private void tsmiDelete_Click(object sender, EventArgs e) //删除文件事件处理
{
if (lvFiles.SelectedItems.Count == 0)
{
return;
}
try
{
string filePath = lvFiles.SelectedItems[0].SubItems[3].Text;
//删除文件
File.Delete(filePath);
//刷新ListView
FillListView(tvDirectories.SelectedNode.Tag.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
第九步,给ContextMenuStrip控件的【复制文件】项,添加Click事件:回到窗体的设计界面,选中ContextMenuStrip控件的【复制文件】项后,双击,进入点击事件,编写代码
private void tsmiCopy_Click(object sender, EventArgs e)//复制文件事件处理
{
if (lvFiles.SelectedItems.Count == 0)
{
return;
}
try
{
//显示选择目录对话框
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK)
{
//复制文件到该目录
string fileName = lvFiles.SelectedItems[0].SubItems[0].Text;
//目标位置
string destPath = fbd.SelectedPath + "\\" + fileName;
//原位置
string filePath = lvFiles.SelectedItems[0].SubItems[3].Text;
File.Copy(filePath, destPath);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
运行测试:(复制文件)
==============这里是结束分割线===================