Roslyn 如何使用 MSBuild Copy 複製文件

本文告訴大家如何在 MSBuild 裏使用 Copy 複製文件

需要知道 Rosyln 是 MSBuild 的 dotnet core 版本。

在 MSBuild 裏可以使用很多命令,本文告訴大家如何使用 Copy 這個 Task 來複制文件

在開始本文之前,希望大家已經知道了一些關於 csproj 文件格式,如果還是不知道,請看理解 C# 項目 csproj 文件格式的本質和編譯流程 - walterlv

最簡單的複製命令請看代碼

  <Copy SourceFiles="lindexi.txt" DestinationFolder="LetirNuhe\" ></Copy>

需要注意,不要把 Copy 直接寫在 Project 下,如下面的代碼

<Project Sdk="Microsoft.NET.Sdk">
     <!-- 忽略代碼 -->
   <Copy SourceFiles="lindexi.txt" DestinationFolder="LetirNuhe\" ></Copy>
</Project>

就會出現下面異常

D:\林德熙\代碼\測試代碼\CemfeetoQewasXaiki\CemfeetoQewasXaiki.csproj : error  : 無法識別元素 <Project> 下面的元素 <Copy>。  D:\林德熙\代碼\測試代碼\CemfeetoQewasXaiki

爲了運行 Copy 需要使用下面代碼

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="LekeexelSurgooHerkassayyayTowjome.txt" DestinationFolder="LetirNuhe\"></Copy>
  </Target>

需要知道 Target 需要給 Name 並且告訴他在什麼時候運行,這裏使用 BeforeTargets 告訴在開始編譯前,也就是複製的文件會被編譯。

對於複製資源文件或需要編譯的資源,就設置 BeforeTargets 在編譯前,如果是不需要進行編譯的文件,如 dll 就可以設置在編譯後運行。

重新生成項目,可以看到文件夾存在文件

如果剛纔沒有創建 文件,複製時找不到文件,就會出現在重新編譯出現無法編譯

error MSB3030: 無法複製文件“lindexi.txt”,原因是找不到該文件

複製有多個方式,下面讓我來一個個和大家說

文件到文件

第一個方法是最簡單的,複製文件到文件

例如我需要複製 lindiexi.txt 到 LetirNuhe\lindexi ,可以使用下面代碼

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="lindexi.txt" DestinationFiles="LetirNuhe\lindexi.txt"></Copy>
  </Target>

那麼如果需要複製多個文件到多個文件?

可以看到 SourceFiles 是可以輸入多個文件,只需要使用;作爲多個文件

下面複製 lindexi.txtlindexi.gitee.io.txtLetirNuhe 文件夾下

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="lindexi.txt;lindexi.gitee.io.txt" DestinationFiles="LetirNuhe\lindexi.txt;LetirNuhe\lindexi.gitee.io.txt"></Copy>
  </Target>

這裏的文件是對應的,也就是第一個文件是 lindexi.txt在 DestinationFiles 也需要寫第一個文件是lindexi.txt的,如果寫爲lindexi2.txt 會自動把 lindexi.txt 複製並且修改名字。第一個文件對應 DestinationFiles 寫的第一個文件,也就是項對應。

因爲從文件複製到文件的代碼太多了,如果只是需要把文件都放在相同的文件夾,可以使用下面的方法

文件到文件夾

如果需要把文件都複製到相同的文件夾,可以使用下面代碼

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="lindexi.txt;lindexi.gitee.io.txt" DestinationFolder="LetirNuhe\"></Copy>
  </Target>

使用 DestinationFolder 指定文件夾,在文件夾不存在的時候會自動創建,剛纔的代碼也是。

文件列表到文件夾

實際上剛纔是寫 SourceFiles ,但是實際這樣寫無法使用通配,也就是*.txt的方法,如果需要使用就需要用文件列表

  <ItemGroup>
    <Txt Include="*.txt"></Txt>
  </ItemGroup>

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="@(Txt)" DestinationFolder="LetirNuhe\"></Copy>
  </Target>

多個文件的列表是在 ItemGroup 裏添加 一個新的標籤,這個標籤是可以自己定義名字的,我這裏定義了 Txt ,讓他包含了 *.txt ,現在就可以在 SourceFiles 使用。使用數組的方法是 @(Txt) ,通過 @ 和 標籤名就可以拿到標籤的文件。如果這時輸出@(Txt) 會看到下面代碼

xx\lindexi.txt;xx\lindexi.gitee.io.txt

因爲 ItemGroup 可以寫多個標籤,可以修改下面代碼

  <ItemGroup>
    <Txt Include="lindexi.txt"></Txt>
    <Txt Include="lindexi.gitee.io.txt"></Txt>
  </ItemGroup>

  <Target Name="Copy" BeforeTargets="CoreCompile">
    <Copy SourceFiles="@(Txt)" DestinationFolder="LetirNuhe\"></Copy>
  </Target>

較新才複製

如果不想每次編譯都複製,可以設置SkipUnchangedFiles="True" 只有在發現文件較新才複製。

判斷文件較新使用的是判斷兩個文件的最後更改時間和文件大小。

軟連接

可以通過設置 UseHardlinksIfPossible="True"不復制文件,而是設置文件的軟連接,也就是修改一個文件可以兩個地方生效

設置軟連接可以做到在多個項目看起來都有自己的文件,但是實際都是指向相同的文件

需要說的是,這個是軟連接,但是在系統是硬連接方式。

判斷文件存在就不復制

如果需要判斷文件存在就不復制,可以使用 Condition 判斷

    <Copy SourceFiles="@(Txt)" DestinationFolder="LetirNuhe\" SkipUnchangedFiles="True" OverwriteReadOnlyFiles="True" Condition="!Exists('LetirNuhe\lindexi.txt')"></Copy>

通過 Exists 判斷文件是否存在,如果存在就不復制。

更多 MSBuild 相關博客請看

理解 C# 項目 csproj 文件格式的本質和編譯流程 - walterlv

如何創建一個基於命令行工具的跨平臺的 NuGet 工具包 - walterlv

如何使用 MSBuild Target(Exec)中的控制檯輸出 - walterlv

更多關於 Roslyn 請看 手把手教你寫 Roslyn 修改編譯

參見:專欄:Roslyn 入門 - CSDN博客


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章