当前位置: 首页 > news >正文

在 MSBuild 编译过程中操作文件和文件夹(检查存在/创建文件夹/读写文件/移动文件/复制文件/删除文件夹)

本文整理 MSBuild 在编译过程中对文件和文件夹处理的各种自带的编译任务(Task)。


本文内容

    • `Exists` 检查文件存在
    • `MakeDir` 创建文件夹
    • `Move` 移动文件
    • `Copy` 复制文件
    • `Delete` 删除文件
    • `ReadLinesFromFile` 读取文件
    • `WriteLinesToFile` 写入文件
    • `RemoveDir` 删除文件夹

Exists 检查文件存在

使用 Exists 可以判断一个文件或者文件夹是否存在。注意无论是文件还是文件夹,只要给定的路径存在就返回 true。可以作为 MSBuild 属性、项和编译任务的执行条件。

<PropertyGroup Condition=" Exists( '$(MSBuildThisFileDirectory)..\build\build.xml' ) ">
    <_WalterlvPackingDirectory>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\</_WalterlvPackingDirectory>
</PropertyGroup>

MakeDir 创建文件夹

下面的例子演示创建一个文件夹:

<Target Name="_WalterlvCreateDirectoryForPacking">
    <MakeDir Directories="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\" />
</Target>

下面是使用到 MakeDir 全部属性的例子,将已经成功创建的文件夹提取出来。

<Target Name="_WalterlvCreateDirectoryForPacking">
    <MakeDir Directories="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\">
        <Output TaskParameter="DirectoriesCreated" PropertyName="CreatedPackingDirectory" />
    </MakeDir>
</Target>

Move 移动文件

下面的例子是将输出文件移动到一个专门的目录中,移动后,所有的文件将平级地在输出文件夹中(即所有的子文件夹中的文件也都被移动到同一层目录中了)。

<PropertyGroup>
    <_WalterlvPackingDirectory>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\</_WalterlvPackingDirectory>
</PropertyGroup>

<Target Name="_WalterlvMoveFilesForPacking">
    <ItemGroup>
        <_WalterlvToMoveFile Include="$(OutputPath)**" />
    </ItemGroup>
    <Move SourceFiles="@(_WalterlvToMoveFile)"
          DestinationFolder="$(_WalterlvPackingDirectory)"
          SkipUnchangedFiles="True" />
</Target>

你可以通过下面的例子了解到 Move 的其他大多数属性及其用法:

<PropertyGroup>
    <_WalterlvPackingDirectory>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\</_WalterlvPackingDirectory>
</PropertyGroup>

<Target Name="_WalterlvMoveFilesForPacking">
    <ItemGroup>
        <_WalterlvToMoveFile Include="$(OutputPath)**" />
        <_WalterlvTargetFile Include="$(_WalterlvPackingDirectory)\%(_WalterlvToMoveFile.RecursiveDir)" />
    </ItemGroup>
    <Move SourceFiles="@(_WalterlvToMoveFile)"
          DestinationFiles="$(_WalterlvTargetFile)"
          OverwriteReadOnlyFiles="True">
        <Output TaskParameter="MovedFiles" PropertyName="MovedOutputFiles" />
    </Copy>
</Target>

这段代码除了没有使用 DestinationFolder 之外,使用到了所有 Move 能用的属性:

  • 将所有的 _WalterlvToCopyFile 一对一地复制到 _WalterlvTargetFile 指定的路径上。
  • 即便目标文件是只读的,也会覆盖。

Copy 复制文件

下面的例子是将输出文件拷贝到一个专门的目录中,保留原来所有文件之间的目录结构,并且如果文件没有改变则跳过。

<PropertyGroup>
    <_WalterlvPackingDirectory>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\</_WalterlvPackingDirectory>
</PropertyGroup>

<Target Name="_WalterlvCopyFilesForPacking">
    <ItemGroup>
        <_WalterlvToCopyFile Include="$(OutputPath)**" />
    </ItemGroup>
    <Copy SourceFiles="@(_WalterlvToCopyFile)"
          DestinationFolder="$(_WalterlvPackingDirectory)\%(RecursiveDir)"
          SkipUnchangedFiles="True" />
</Target>

如果你希望复制后所有的文件都在同一级文件夹中,不再有子文件夹,那么去掉 \%(RecursiveDir)

你可以通过下面的例子了解到 Copy 的其他大多数属性及其用法:

<PropertyGroup>
    <_WalterlvPackingDirectory>$(MSBuildThisFileDirectory)..\bin\$(Configuration)\</_WalterlvPackingDirectory>
</PropertyGroup>

<Target Name="_WalterlvCopyFilesForPacking">
    <ItemGroup>
        <_WalterlvToCopyFile Include="$(OutputPath)**" />
        <_WalterlvTargetFile Include="$(_WalterlvPackingDirectory)\%(_WalterlvToCopyFile.RecursiveDir)" />
    </ItemGroup>
    <Copy SourceFiles="@(_WalterlvToCopyFile)"
          DestinationFiles="@(_WalterlvTargetFile)"
          OverwriteReadOnlyFiles="True"
          Retries="10"
          RetryDelayMilliseconds="10"
          SkipUnchangedFiles="True"
          UseHardlinksIfPossible="True">
        <Output TaskParameter="CopiedFiles" PropertyName="CopiedOutputFiles" />
    </Copy>
</Target>

这段代码除了没有使用 DestinationFolder 之外,使用到了所有 Copy 能用的属性:

  • 将所有的 _WalterlvToCopyFile 一对一地复制到 _WalterlvTargetFile 指定的路径上。
  • 即便目标文件是只读的,也会覆盖。
  • 如果复制失败,则重试 10 次,每次等待 10 毫秒
  • 如果文件没有改变,则跳过复制
  • 如果目标文件系统支持硬连接,则使用硬连接来提升性能

Delete 删除文件

下面这个例子是删除输出目录下的所有的 pdb 文件(适合 release 下发布软件)。

<Target Name="_WalterlvDeleteFiles">
    <Delete Files="$(OutputPath)*.pdb" />
</Target>

也可以把此操作已经删除的文件列表拿出来。使用全部属性的 Delete 的例子:


<Target Name="_WalterlvDeleteFiles">
    <Delete Files="$(OutputPath)*.pdb" TreatErrorsAsWarnings="True">
        <Output TaskParameter="DeletedFiles" PropertyName="DeletedPdbFiles" />
    </Delete>
</Target>

ReadLinesFromFile 读取文件

在编译期间,可以从文件中读出文件的每一行:

<PropertyGroup>
    <_WalterlvToWriteFile>$(OutputPath)walterlv.md</_WalterlvToWriteFile>
</PropertyGroup>

<Target Name="_WalterlvReadFilesToLines">
    <ReadLinesFromFile File="$(_WalterlvToWriteFile)">
        <Output TaskParameter="Lines" PropertyName="TheLinesThatRead" />
    </ReadLinesFromFile>
</Target>

WriteLinesToFile 写入文件

可以在编译期间,将一些信息写到文件中以便后续编译的时候使用,甚至将代码写到文件中以便动态生成代码。

<PropertyGroup>
    <_WalterlvBlogSite>https://blog.walterlv.com</_WalterlvBlogSite>
    <_WalterlvToWriteFile>$(OutputPath)walterlv.md</_WalterlvToWriteFile>
</PropertyGroup>

<ItemGroup>
    <_WalterlvToWriteLine Include="This is the first line" />
    <_WalterlvToWriteLine Include="This is the second line" />
    <_WalterlvToWriteLine Include="My blog site is: $(_WalterlvBlogSite)" />
</ItemGroup>

<Target Name="_WalterlvWriteFilesForPacking">
    <WriteLinesToFile File="$(_WalterlvToWriteFile)"
                      Lines="@(_WalterlvToWriteLine)" />
</Target>

▲ 注意,默认写入文件是不会覆盖的,会将内容补充到原来文件的后面。

<Target Name="_WalterlvWriteFilesForPacking">
    <WriteLinesToFile File="$(_WalterlvToWriteFile)"
                      Lines="@(_WalterlvToWriteLine)"
                      Overwrite="True"
                      Encoding="Unicode"
                      WriteOnlyWhenDifferent="True" />
</Target>

RemoveDir 删除文件夹

在编写编译命令的时候,可能会涉及到清理资源。或者为了避免无关文件的影响,在编译之前删除我们的工作目录。

<Target Name="_WalterlvRemoveDirectoryForPacking">
    <RemoveDir Directories="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\" />
</Target>

下面是使用到 MakeDir 全部属性的例子,将已经成功创建的文件夹提取出来。

<Target Name="_WalterlvRemoveDirectoryForPacking">
    <RemoveDir Directories="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\">
        <Output TaskParameter="RemovedDirectories" PropertyName="RemovedPackingDirectory" />
    </RemoveDir>
</Target>

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 在 WPF 程序中应用 Windows 10 真•亚克力效果
  • 推荐 .NET/C# 开发者安装的几款代码分析插件或对应的代码分析 NuGet 包
  • 在 HTML 超链接上添加可交互的 ToolTip
  • 在移动端打开 Google 的网页快照
  • 为自己搭建的博客添加可切换的暗色和亮色主题
  • 如何编写基于 Microsoft.NET.Sdk 的跨平台的 MSBuild Target(附各种自带的 Task)
  • 让你编写的控件库在 XAML 中有一个统一的漂亮的命名空间(xmlns)和命名空间前缀
  • Sdk 风格的 csproj 对 WPF/UWP 支持不太好?有第三方 SDK 可以用!MSBuild.Sdk.Extras
  • 为博客或个人站点的 Markdown 添加 LaTeX 公式支持
  • 如何让 .NET Core 命令行程序接受密码的输入而不显示密码明文
  • 如何编写 WPF 的标记扩展 MarkupExtension,即便在 ControlTemplate/DataTemplate 中也能生效
  • PasswordVault —— 在 UWP 应用中安全地保存密码
  • 如何在 MSBuild Target(Exec)中报告编译错误和编译警告
  • 将 .NET Core 项目打一个最简单的 NuGet 源码包,安装此包就像直接把源码放进项目一样
  • 使用 LINQ to XML,.NET 让生成 XML 文件变得和直接写 XML 一样轻松
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • CentOS从零开始部署Nodejs项目
  • chrome扩展demo1-小时钟
  • hadoop集群管理系统搭建规划说明
  • mysql常用命令汇总
  • uni-app项目数字滚动
  • 后端_MYSQL
  • 力扣(LeetCode)357
  • 入门级的git使用指北
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 优秀架构师必须掌握的架构思维
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • linux 淘宝开源监控工具tsar
  • Mac 上flink的安装与启动
  • 大数据全解:定义、价值及挑战
  • 我们雇佣了一只大猴子...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​卜东波研究员:高观点下的少儿计算思维
  • # 透过事物看本质的能力怎么培养?
  • #pragma 指令
  • $NOIp2018$劝退记
  • (笔试题)合法字符串
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (九十四)函数和二维数组
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)拼包函数及网络封包的异常处理(含代码)
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .Net - 类的介绍
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net 7 上传文件踩坑
  • .net core 6 redis操作类
  • .net core 连接数据库,通过数据库生成Modell
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .NET牛人应该知道些什么(2):中级.NET开发人员